diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..2491d42 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Andreas Habel +Bjørn Lindeijer +Mpa4Hu +seeseekey \ No newline at end of file diff --git a/CONTRIBUTES b/CONTRIBUTES index 396889e..788f295 100644 --- a/CONTRIBUTES +++ b/CONTRIBUTES @@ -1,86 +1,86 @@ -/** - * The Mana World Webinterface - * Copyright 2008 The Mana World Development Team - * - * This file is part of The Mana World. - * - * The Mana World is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or any later version. - * - * The Mana World 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. - * - * You should have received a copy of the GNU General Public License along - * with The Mana World; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -This file contains a list of all external resources used by manaweb: -(sorted by their time of integration into manaweb) - -PHP CodeIgniterFramework -------------------------- - "CodeIgniter is a powerful PHP framework with a very small footprint, - built for PHP coders who need a simple and elegant toolkit to create - full-featured web applications. If you're a developer who lives in the - real world of shared hosting accounts and clients with deadlines, and - if you're tired of ponderously large and thoroughly undocumented - frameworks" - - http://codeigniter.com/ - License: ./licenses/CodeIgniter.txt - - -JpGraph --------- - "JpGraph is a Object-Oriented Graph creating library for PHP >= 4.3.1 The - library is completely written in PHP and ready to be used in any PHP - scripts (both CGI/APXS/CLI versions of PHP are supported). - - The library can be used to create numerous types of graphs either on-line - or written to a file. JpGraph makes it easy to draw both "quick and dirty" - graphs with a minimum of code as well as complex graphs which requires a - very fine grained control. The library assigns context sensitive default - values for most of the parameters which minimizes the learning curve. The - features are there when you need them - not as an obstacle to overcome!" - - http://www.aditus.nu/jpgraph/ - License: ./licenses/JPGraph.txt - - -Tango Desktop Project ----------------------- - "The Tango Desktop Project exists to help create a consistent graphical - user interface experience for free and Open Source software." - - Manaweb uses some icons of this project as long as mana has not its own set - of icons. (some of them got recoloured to match the style of manaweb) - - http://tango.freedesktop.org - License: ./licenses/Tango Desktop Project.txt - - -script.aculo.us ---------------- - - "The Web is changing. The 30-year-old terminal-like technology it was - originally is gradually giving way to new ways of doing things. The power - of AJAX allows for rich user interaction without the trouble that has - bugged traditional web applications. - - Building upon the wonderful Prototype JavaScript library, script.aculo.us - provides you with some great additional ingredients to mix in." - - http://script.aculo.us/ - License: ./licenses/Scriptaculous.txt - -DHTMLSuite for applications ---------------------------- - - todo - - http://www.dhtmlgoodies.com/index.html?page=dhtml-suite - License: ./licenses/DHTMLSuite-for-Applications.txt +/** + * The Mana World Webinterface + * Copyright 2008 - 2011 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or any later version. + * + * The Mana World 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. + * + * You should have received a copy of the GNU General Public License along + * with The Mana World; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +This file contains a list of all external resources used by manaweb: +(sorted by their time of integration into manaweb) + +PHP CodeIgniterFramework +------------------------- + "CodeIgniter is a powerful PHP framework with a very small footprint, + built for PHP coders who need a simple and elegant toolkit to create + full-featured web applications. If you're a developer who lives in the + real world of shared hosting accounts and clients with deadlines, and + if you're tired of ponderously large and thoroughly undocumented + frameworks" + + http://codeigniter.com/ + License: ./licenses/CodeIgniter.txt + + +JpGraph +-------- + "JpGraph is a Object-Oriented Graph creating library for PHP >= 4.3.1 The + library is completely written in PHP and ready to be used in any PHP + scripts (both CGI/APXS/CLI versions of PHP are supported). + + The library can be used to create numerous types of graphs either on-line + or written to a file. JpGraph makes it easy to draw both "quick and dirty" + graphs with a minimum of code as well as complex graphs which requires a + very fine grained control. The library assigns context sensitive default + values for most of the parameters which minimizes the learning curve. The + features are there when you need them - not as an obstacle to overcome!" + + http://www.aditus.nu/jpgraph/ + License: ./licenses/JPGraph.txt + + +Tango Desktop Project +---------------------- + "The Tango Desktop Project exists to help create a consistent graphical + user interface experience for free and Open Source software." + + Manaweb uses some icons of this project as long as mana has not its own set + of icons. (some of them got recoloured to match the style of manaweb) + + http://tango.freedesktop.org + License: ./licenses/Tango Desktop Project.txt + + +script.aculo.us +--------------- + + "The Web is changing. The 30-year-old terminal-like technology it was + originally is gradually giving way to new ways of doing things. The power + of AJAX allows for rich user interaction without the trouble that has + bugged traditional web applications. + + Building upon the wonderful Prototype JavaScript library, script.aculo.us + provides you with some great additional ingredients to mix in." + + http://script.aculo.us/ + License: ./licenses/Scriptaculous.txt + +DHTMLSuite for applications +--------------------------- + + todo + + http://www.dhtmlgoodies.com/index.html?page=dhtml-suite + License: ./licenses/DHTMLSuite-for-Applications.txt diff --git a/README b/README index 1aafd2e..73d6357 100644 --- a/README +++ b/README @@ -1,166 +1,166 @@ -The Mana Server - Account Manager -================================ - -Contents -======== -1. Installation Instructions and requirements -2. Configuration notes -3. Troubleshooting -4. Translations -5. Maintenance -6. Contact and support - - -============================================================================= - -1. INSTALLATION INSTRUCTIONS AND REQUIREMENTS - -You will need a web server running PHP 5.1 or later, with pdo_sqlite. -On FreeBSD you will need to install ports databases/php5-pdo_sqlite and -security/pecl-hash along with lang/php5. - - -============================================================================= - -2. CONFIGURATION NOTES - -There are several config files that have to be prepared for your specific -environment. You can find all config files under ./system/application/config - -Manweb comes with a default configuration file called "config.default.php" You -should use this file as template to set up your individual configuration. Make -a copy of this file and name rename it to "config.php". In general you have to -modify the following settings: - - * set the "base_url" to the url of your installation. - * define the desired "log_threshold" to your needs - -Do the same with the file "database.default.php" and "email.default.php". -Rename them to "database.php" and "email.php" configure the options inside -for your needs. - -The following configuration files are shipped with defaults that may or may not -be suitable for you. - - * menu.php - * mana_config.php - -Instead of modifying the files directly you should make a copy of them and -rename them to .user.php, so "menu.php" gets "menu.user.php". -Manweb first loads menu.php, afterwards menu.user.php (if it exists) and -overrides the default values with your custom settings. The advantage of this -method is, that upgrading manaweb won't break your configuration. - -All other files in the config directory shouldn`t get touched by you! - - -After proper configuration of all files you have to ensure that the webserver -has write access to the ./system/logs, the ./images/items and ./data directory. - - chmod 777 ./system/logs - chmod 777 ./data - chmod 777 ./images/items - -Manaweb tries to store cached data read from other modules like manaserv in the -data directory for faster access. Therefore you should allow the webserver to -create files there. The logs directory is used for logging as you can think. - -To verify your installation and configuration steps, navigate to the setup.php -file in your browser. It will show you what is still missing or if everything -is fine. - -============================================================================= - -3. TROUBLESHOOTING - -After uploading and configuring manaweb it might happen that every site you -call is only white and blank. Lets set loglevel in config.php to 4 and after -refreshing your site in the browser have a look at the logfiles under -./system/logs -If there is no file except index.html please recheck your directory -permissions. Again, the webserver needs write permissions to ./system/logs -If you cannot find a file that is named "config.php", please go back to chapter -2 and read it more carefully! - - -============================================================================= - -4. TRANSLATIONS - -Manaweb has simple multilanguage support integrated. During login into your -account you can choose one of the currently translated languages. If your -native language is not available yet, feel free to support the dev team and -translate manaweb. -To start with a new language there are two simple steps to do: - a.) copy the directoy ./system/application/language/english as it is the - shipped language with manaweb and should contain all necessary strings. - Also you have to copy ./system/language/english to your new language. - This directory contains string comming from CodeIgniter, the used - php framework. - Ensure not to copy the hidden directory .svn if you checked - out from subversion. Each php file ending with *_lang.php needs to be - translated. - - $lang['character'] = ''; - - Ensure to double quote '' inside of your strings if necessary. - - b.) At least you have to add your new language to the config file - manaweb/system/application/conf/mana_conf.php - Just add your language to the array $_mana_languages like shown below. - The parameter 'dir' has to be the name of your added directory, maybe - 'german'. 'name' is the displayed string during login. This should be - the native name of the language, like 'deutsch'. - Don't forget a comma to separate language arrays. - - $_mana_languages = array( - array('dir'=>'english', 'name'=>'english'), - array('dir'=>'german', 'name'=>'deutsch') - ); - - -============================================================================= - -5. MAINTENANCE - -The intention of manaweb is to be a slim, administrative frontend for manaserv. -Therfore it is natural to use as much as data, information and configuration we -can get from manaserv. Because manaserv makes extensive use of xml configuration -files, which would be too expensive to parse on every page request, manaweb uses -different methods to cache those informations for faster access. - -From time to time, if the data in manaserv was modified, a admin user has to -refresh the caches of manaweb. Therefor you can find a menuoption "maintance" -when logged in with an administrative account. This page shows you all caches -and allows you to refresh them with a single click. - -items.xml ---------- -Refreshing the items database is a bit special, thats why it is mentioned here -additionally. -To show the inventory of a character, the images of those items have to be -available for a webbrowser. Therfore they have to reside somewhere -under the DOCUMENT_ROOT of your webserver. To keep all things together, we -decided to store them under ./images/items. When refreshing the items database, -manaweb looks in that directory and compares the images located there to all -items in the database. If a image is missing, manaweb tries to copy this image -from your manadata path, you can configure in mana_config.php (see chapter 2). -To copy those images, the webserver needs write permission to the images/items -directory. If manaweb can't find the image in the manadata directory is is not -allowed to write to the ./images/items directory, the refresh procedure will -show you a list with all missing images. Then you will have to copy those -images yourself. - -============================================================================= - -6. CONTACT AND SUPPORT - -For support please refer to the well know places like -Wiki: http://wiki.manasource.org, the forum under -Forum: http://forums.manasource.org/index.php -Bugs: http://bugs.manasource.org -IRC: irc.freenode.net #manasource - - -Direct link to the Account manager wiki page: -http://wiki.manasource.org/index.php/Account_Manager +The Mana Server - Account Manager +================================ + +Contents +======== +1. Installation Instructions and requirements +2. Configuration notes +3. Troubleshooting +4. Translations +5. Maintenance +6. Contact and support + + +============================================================================= + +1. INSTALLATION INSTRUCTIONS AND REQUIREMENTS + +You will need a web server running PHP 5.1 or later, with pdo_sqlite. +On FreeBSD you will need to install ports databases/php5-pdo_sqlite and +security/pecl-hash along with lang/php5. + + +============================================================================= + +2. CONFIGURATION NOTES + +There are several config files that have to be prepared for your specific +environment. You can find all config files under ./system/application/config + +Manweb comes with a default configuration file called "config.default.php" You +should use this file as template to set up your individual configuration. Make +a copy of this file and name rename it to "config.php". In general you have to +modify the following settings: + + * set the "base_url" to the url of your installation. + * define the desired "log_threshold" to your needs + +Do the same with the file "database.default.php" and "email.default.php". +Rename them to "database.php" and "email.php" configure the options inside +for your needs. + +The following configuration files are shipped with defaults that may or may not +be suitable for you. + + * menu.php + * mana_config.php + +Instead of modifying the files directly you should make a copy of them and +rename them to .user.php, so "menu.php" gets "menu.user.php". +Manweb first loads menu.php, afterwards menu.user.php (if it exists) and +overrides the default values with your custom settings. The advantage of this +method is, that upgrading manaweb won't break your configuration. + +All other files in the config directory shouldn`t get touched by you! + + +After proper configuration of all files you have to ensure that the webserver +has write access to the ./system/logs, the ./images/items and ./data directory. + + chmod 777 ./system/logs + chmod 777 ./data + chmod 777 ./images/items + +Manaweb tries to store cached data read from other modules like manaserv in the +data directory for faster access. Therefore you should allow the webserver to +create files there. The logs directory is used for logging as you can think. + +To verify your installation and configuration steps, navigate to the setup.php +file in your browser. It will show you what is still missing or if everything +is fine. + +============================================================================= + +3. TROUBLESHOOTING + +After uploading and configuring manaweb it might happen that every site you +call is only white and blank. Lets set loglevel in config.php to 4 and after +refreshing your site in the browser have a look at the logfiles under +./system/logs +If there is no file except index.html please recheck your directory +permissions. Again, the webserver needs write permissions to ./system/logs +If you cannot find a file that is named "config.php", please go back to chapter +2 and read it more carefully! + + +============================================================================= + +4. TRANSLATIONS + +Manaweb has simple multilanguage support integrated. During login into your +account you can choose one of the currently translated languages. If your +native language is not available yet, feel free to support the dev team and +translate manaweb. +To start with a new language there are two simple steps to do: + a.) copy the directoy ./system/application/language/english as it is the + shipped language with manaweb and should contain all necessary strings. + Also you have to copy ./system/language/english to your new language. + This directory contains string comming from CodeIgniter, the used + php framework. + Ensure not to copy the hidden directory .svn if you checked + out from subversion. Each php file ending with *_lang.php needs to be + translated. + + $lang['character'] = ''; + + Ensure to double quote '' inside of your strings if necessary. + + b.) At least you have to add your new language to the config file + manaweb/system/application/conf/mana_conf.php + Just add your language to the array $_mana_languages like shown below. + The parameter 'dir' has to be the name of your added directory, maybe + 'german'. 'name' is the displayed string during login. This should be + the native name of the language, like 'deutsch'. + Don't forget a comma to separate language arrays. + + $_mana_languages = array( + array('dir'=>'english', 'name'=>'english'), + array('dir'=>'german', 'name'=>'deutsch') + ); + + +============================================================================= + +5. MAINTENANCE + +The intention of manaweb is to be a slim, administrative frontend for manaserv. +Therfore it is natural to use as much as data, information and configuration we +can get from manaserv. Because manaserv makes extensive use of xml configuration +files, which would be too expensive to parse on every page request, manaweb uses +different methods to cache those informations for faster access. + +From time to time, if the data in manaserv was modified, a admin user has to +refresh the caches of manaweb. Therefor you can find a menuoption "maintance" +when logged in with an administrative account. This page shows you all caches +and allows you to refresh them with a single click. + +items.xml +--------- +Refreshing the items database is a bit special, thats why it is mentioned here +additionally. +To show the inventory of a character, the images of those items have to be +available for a webbrowser. Therfore they have to reside somewhere +under the DOCUMENT_ROOT of your webserver. To keep all things together, we +decided to store them under ./images/items. When refreshing the items database, +manaweb looks in that directory and compares the images located there to all +items in the database. If a image is missing, manaweb tries to copy this image +from your manadata path, you can configure in mana_config.php (see chapter 2). +To copy those images, the webserver needs write permission to the images/items +directory. If manaweb can't find the image in the manadata directory is is not +allowed to write to the ./images/items directory, the refresh procedure will +show you a list with all missing images. Then you will have to copy those +images yourself. + +============================================================================= + +6. CONTACT AND SUPPORT + +For support please refer to the well know places like +Wiki: http://wiki.manasource.org, the forum under +Forum: http://forums.manasource.org/index.php +Bugs: http://bugs.manasource.org +IRC: irc.freenode.net #manasource + + +Direct link to the Account manager wiki page: +http://wiki.manasource.org/index.php/Account_Manager diff --git a/TODO b/TODO index b72a279..cf91220 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ -* Optimize setup process. index.php should route to setup.php until the setup - is not yet finished. -* Implement a themes manager and the possibility to easy switch between - styles. -* Add gettext support for translations. +* Optimize setup process. index.php should route to setup.php until the setup + is not yet finished. +* Implement a themes manager and the possibility to easy switch between + styles. +* replace table namens in maintenance.php \ No newline at end of file diff --git a/data/index.html b/data/index.html index c942a79..065d2da 100644 --- a/data/index.html +++ b/data/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

Directory access is forbidden.

- - + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + \ No newline at end of file diff --git a/data/themes/default/default.css b/data/themes/default/default.css index 9a5aa7b..1060ef5 100644 --- a/data/themes/default/default.css +++ b/data/themes/default/default.css @@ -1,280 +1,280 @@ -/* ///////////////////////////////////////////////////////////////////////////// -basic elements -///////////////////////////////////////////////////////////////////////////// */ -body { - background-color: #fffcf2; - padding: 0px 10px 10px 10px; - margin: 0px; - font-family: sans-serif; - background-image: url(images/layout/headbar.png); - background-repeat: repeat-x; - background-position: 0px -25px; -} - -body, div, p, td, li, h1, h2, h3, h4 { - font-family: 'Verdana', sans-serif; - font-size: 10pt; -} - -#logo { - position: absolute; - width: 153px; - height: 97px; - margin: 0px; - top: 0px; - left: 10px; - background-image: url(images/layout/header.png); - background-repeat: no-repeat; - background-position: 0px 0px; - z-index:400; -} - -/* Links */ -a { color: #ff6600; text-decoration: none; } -a:link { color: #ff6600; text-decoration: none; } -a:visited { color: #ff6600; text-decoration: none; } -a:focus { color: #ff3300; text-decoration: none; } -a:hover { color: #ff3300; text-decoration: none; } -a:active { color: #ff3300; text-decoration: none; } - -hr { - border-style: none; - height: 1px; - background-color: silver; - color: silver; -} - - -/* ///////////////////////////////////////////////////////////////////////////// -named elements -///////////////////////////////////////////////////////////////////////////// */ - -#page { - padding: 110px 0px 0px 0px; -} - -#contents -{ - padding: 15px 10px 0px 230px; - -} - -#contents h1 { - - margin: 0px; - color: #57565c; - font-size: 16pt; -} - -#contents h2 { - padding: 7px 7px 7px 107px; - margin: 0px; - color: #57565c; - font-size: 16pt; -} - -#contents h3 { - margin: 20px 0px 10px 0px; - - font-weight: bold; - color: #3c3c3c; - border-bottom: 1px solid #9f9894; - font-size: 11pt; -} - -#contents label { - margin: 5px; - padding: 5px 5px 5px 15px; - white-space: nowrap; - font-weight: bold; - text-align: right; -} - -#contents span.label { - margin: 5px; - padding: 10px 5px 5px 15px; - white-space: nowrap; - font-weight: bold; -} - -#contents span.input { - padding: 1px 10px 1px 10px; - margin: 5px; - color: #57565c; - font-size: 11pt; - background-color: #eeeeee; - border: 1px solid #9f9894; - -moz-border-radius: 4px; -} - -#contents input { - padding: 4px 10px 4px 10px; - margin: 5px; - color: #57565c; - font-size: 11pt; - background-color: #eeeeee; - border: 1px solid #9f9894; - -moz-border-radius: 10px; -} - -#contents select { - padding: 4px 10px 4px 10px; - margin: 5px; - color: #57565c; - font-size: 11pt; - background-color: #eeeeee; - border: 1px solid #9f9894; - -moz-border-radius: 10px; -} - -#contents .datatable -{ - padding: 5px 0px 0px 0px; - color: #57565c; - background-color: #eeeeee; - border: 1px solid #9f9894; - -moz-border-radius: 10px; - width: 100%; -} - -#contents .datatable td -{ - border: 1px dotted #cccccc; - padding: 0px; -} - -/* ///////////////////////////////////////////////////////////////////////////// -sidebar -///////////////////////////////////////////////////////////////////////////// */ - -#sidebar -{ - float: left; - width: 200px; - padding-top: 2px; -} - -#sidebar .navbox .navheader -{ - width: 200px; - height: 35px; - background-image: url(images/layout/nav_head.png); -} - -#sidebar .navbox .navheader h1 -{ - padding: 10px 0px 0px 30px; - font-weight: bold; -} - -#sidebar .navbox .navbody -{ - width: 200px; - background-image: url(images/layout/nav_body.png); - background-repeat: repeat-y; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; - border: none; -} - -#sidebar .navbox .navbody ul -{ - margin: 0px; - padding: 0px; -} - -#sidebar .navbox .navbody li { - list-style: none; - margin: 0px; -} - -#sidebar .navbox .navbody li a { - display: block; - margin: 0px; - width: auto; - text-decoration: none; - padding: 5px 5px 5px 20px; - margin: 0px; - color: black; - font-style: normal; -} - -#sidebar .navbox .navbody a:hover { - background-image: url(images/layout/nav_body_hover.png); - background-repeat: repeat-y; - -} - -#sidebar .navbox .navfooter -{ - width: 200px; - height: 43px; - padding: 0px 0px 0px 0px; - margin: 0px 0px 0px 0px; - background-image: url(images/layout/nav_footer.png); - -} - - - - - - - - -/* ///////////////////////////////////////////////////////////////////////////// -style elements -///////////////////////////////////////////////////////////////////////////// */ - -img.online-led { - vertical-align: text-bottom; - padding: 0px 1px 0px 1px; -} - -#footer -{ - font-size: 8pt; - text-align: center; - padding: 5px; - margin-top: 20px; - border-top: 1px dashed gray; - width: auto; -} - -/* ///////////////////////////////////////////////////////////////////////////// -javascript features -///////////////////////////////////////////////////////////////////////////// */ - -#contents div.autocomplete { - margin: 3px 3px 3px 3px; - padding: 7px 7px 7px 7px; - width:250px; - background-color: #eeeeee; - border: 1px solid #9f9894; - position:absolute; - -moz-border-radius: 10px; -} - -#contents div.autocomplete ul { - margin:0px; - padding:0px; - list-style-type:none; - list-style-image:none; -} - -#contents div.autocomplete ul li.selected { - color: #ff6600; -} - -#contents div.autocomplete ul li { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; - height:18px; - display:block; - list-style-type:none; - list-style-image:none; - cursor:pointer; - color:#57565c; -} - -/* ////////////////////// end of file /////////////////////////////////////// */ +/* ///////////////////////////////////////////////////////////////////////////// +basic elements +///////////////////////////////////////////////////////////////////////////// */ +body { + background-color: #fffcf2; + padding: 0px 10px 10px 10px; + margin: 0px; + font-family: sans-serif; + background-image: url(images/layout/headbar.png); + background-repeat: repeat-x; + background-position: 0px -25px; +} + +body, div, p, td, li, h1, h2, h3, h4 { + font-family: 'Verdana', sans-serif; + font-size: 10pt; +} + +#logo { + position: absolute; + width: 153px; + height: 97px; + margin: 0px; + top: 0px; + left: 10px; + background-image: url(images/layout/header.png); + background-repeat: no-repeat; + background-position: 0px 0px; + z-index:400; +} + +/* Links */ +a { color: #ff6600; text-decoration: none; } +a:link { color: #ff6600; text-decoration: none; } +a:visited { color: #ff6600; text-decoration: none; } +a:focus { color: #ff3300; text-decoration: none; } +a:hover { color: #ff3300; text-decoration: none; } +a:active { color: #ff3300; text-decoration: none; } + +hr { + border-style: none; + height: 1px; + background-color: silver; + color: silver; +} + + +/* ///////////////////////////////////////////////////////////////////////////// +named elements +///////////////////////////////////////////////////////////////////////////// */ + +#page { + padding: 110px 0px 0px 0px; +} + +#contents +{ + padding: 15px 10px 0px 230px; + +} + +#contents h1 { + + margin: 0px; + color: #57565c; + font-size: 16pt; +} + +#contents h2 { + padding: 7px 7px 7px 107px; + margin: 0px; + color: #57565c; + font-size: 16pt; +} + +#contents h3 { + margin: 20px 0px 10px 0px; + + font-weight: bold; + color: #3c3c3c; + border-bottom: 1px solid #9f9894; + font-size: 11pt; +} + +#contents label { + margin: 5px; + padding: 5px 5px 5px 15px; + white-space: nowrap; + font-weight: bold; + text-align: right; +} + +#contents span.label { + margin: 5px; + padding: 10px 5px 5px 15px; + white-space: nowrap; + font-weight: bold; +} + +#contents span.input { + padding: 1px 10px 1px 10px; + margin: 5px; + color: #57565c; + font-size: 11pt; + background-color: #eeeeee; + border: 1px solid #9f9894; + -moz-border-radius: 4px; +} + +#contents input { + padding: 4px 10px 4px 10px; + margin: 5px; + color: #57565c; + font-size: 11pt; + background-color: #eeeeee; + border: 1px solid #9f9894; + -moz-border-radius: 10px; +} + +#contents select { + padding: 4px 10px 4px 10px; + margin: 5px; + color: #57565c; + font-size: 11pt; + background-color: #eeeeee; + border: 1px solid #9f9894; + -moz-border-radius: 10px; +} + +#contents .datatable +{ + padding: 5px 0px 0px 0px; + color: #57565c; + background-color: #eeeeee; + border: 1px solid #9f9894; + -moz-border-radius: 10px; + width: 100%; +} + +#contents .datatable td +{ + border: 1px dotted #cccccc; + padding: 0px; +} + +/* ///////////////////////////////////////////////////////////////////////////// +sidebar +///////////////////////////////////////////////////////////////////////////// */ + +#sidebar +{ + float: left; + width: 200px; + padding-top: 2px; +} + +#sidebar .navbox .navheader +{ + width: 200px; + height: 35px; + background-image: url(images/layout/nav_head.png); +} + +#sidebar .navbox .navheader h1 +{ + padding: 10px 0px 0px 30px; + font-weight: bold; +} + +#sidebar .navbox .navbody +{ + width: 200px; + background-image: url(images/layout/nav_body.png); + background-repeat: repeat-y; + padding: 0px 0px 0px 0px; + margin: 0px 0px 0px 0px; + border: none; +} + +#sidebar .navbox .navbody ul +{ + margin: 0px; + padding: 0px; +} + +#sidebar .navbox .navbody li { + list-style: none; + margin: 0px; +} + +#sidebar .navbox .navbody li a { + display: block; + margin: 0px; + width: auto; + text-decoration: none; + padding: 5px 5px 5px 20px; + margin: 0px; + color: black; + font-style: normal; +} + +#sidebar .navbox .navbody a:hover { + background-image: url(images/layout/nav_body_hover.png); + background-repeat: repeat-y; + +} + +#sidebar .navbox .navfooter +{ + width: 200px; + height: 43px; + padding: 0px 0px 0px 0px; + margin: 0px 0px 0px 0px; + background-image: url(images/layout/nav_footer.png); + +} + + + + + + + + +/* ///////////////////////////////////////////////////////////////////////////// +style elements +///////////////////////////////////////////////////////////////////////////// */ + +img.online-led { + vertical-align: text-bottom; + padding: 0px 1px 0px 1px; +} + +#footer +{ + font-size: 8pt; + text-align: center; + padding: 5px; + margin-top: 20px; + border-top: 1px dashed gray; + width: auto; +} + +/* ///////////////////////////////////////////////////////////////////////////// +javascript features +///////////////////////////////////////////////////////////////////////////// */ + +#contents div.autocomplete { + margin: 3px 3px 3px 3px; + padding: 7px 7px 7px 7px; + width:250px; + background-color: #eeeeee; + border: 1px solid #9f9894; + position:absolute; + -moz-border-radius: 10px; +} + +#contents div.autocomplete ul { + margin:0px; + padding:0px; + list-style-type:none; + list-style-image:none; +} + +#contents div.autocomplete ul li.selected { + color: #ff6600; +} + +#contents div.autocomplete ul li { + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + height:18px; + display:block; + list-style-type:none; + list-style-image:none; + cursor:pointer; + color:#57565c; +} + +/* ////////////////////// end of file /////////////////////////////////////// */ diff --git a/data/themes/default/theme.php b/data/themes/default/theme.php index 4310205..aba3222 100644 --- a/data/themes/default/theme.php +++ b/data/themes/default/theme.php @@ -1,64 +1,64 @@ -"; - } - - public function beforeNavigationBar() - { - return "
"; - } - - public function afterNavigationBar() - { - return "
"; - } - - public function beforeNavigationBox() - { - return "
"; - } - - public function NavigationBox(NavigationBox $box) - { - $str = " -

" . $box->getHeader() . "

-
-
    "; - - foreach( $box->getItems() as $item ) - { - $str .= sprintf("
  • %s
  • \n", - $item->getUrl(), $item->getText() - ); - } - $str .= "
\n"; - return $str; - } - - public function afterNavigationBox() - { - return "
 
-
\n"; - } - - public function beforeContent() - { - return "
"; - } - - public function afterContent() - { - return "
-
"; - } - -} - -?> +
"; + } + + public function beforeNavigationBar() + { + return "
"; + } + + public function afterNavigationBar() + { + return "
"; + } + + public function beforeNavigationBox() + { + return "
"; + } + + public function NavigationBox(NavigationBox $box) + { + $str = " +

" . $box->getHeader() . "

+
+
    "; + + foreach( $box->getItems() as $item ) + { + $str .= sprintf("
  • %s
  • \n", + $item->getUrl(), $item->getText() + ); + } + $str .= "
\n"; + return $str; + } + + public function afterNavigationBox() + { + return "
 
+
\n"; + } + + public function beforeContent() + { + return "
"; + } + + public function afterContent() + { + return "
+
"; + } + +} + +?> diff --git a/data/themes/default/theme.xml b/data/themes/default/theme.xml index 77d3a69..1df4310 100644 --- a/data/themes/default/theme.xml +++ b/data/themes/default/theme.xml @@ -1,12 +1,12 @@ - - - - Manaweb default theme - Andreas Habel - 1.0.0 - - theme.php - default.css - DefaultTheme - - + + + + Manaweb default theme + Andreas Habel + 1.0.0 + + theme.php + default.css + DefaultTheme + + diff --git a/data/themes/tmw/default.css b/data/themes/tmw/default.css index c9b1eff..80f06a1 100644 --- a/data/themes/tmw/default.css +++ b/data/themes/tmw/default.css @@ -1,419 +1,419 @@ -/* ///////////////////////////////////////////////////////////////////////////// -basic elements -///////////////////////////////////////////////////////////////////////////// */ -body { - background-color: #eeeeee; - padding: 0px 10px 10px 10px; - margin: 0px; - font-family: sans-serif; -} - -body, div, p, td, li, h1, h2, h3, h4 { - font-family: sans-serif; - font-size: 10pt; -} - -h1 { - background-image: url(images/layout/header.png); - background-repeat: no-repeat; - position: absolute; - width: 600px; - height: 210px; - margin: 0px; - top: 0px; - border: 0px solid green; - z-index:200; -} - -a { - text-decoration: none; - color: rgb(100,10,10); -} - -a:visited { - color: rgb(60,0,0); -} - -a:hover { - text-decoration: underline; -} - -hr { - border-style: none; - height: 1px; - background-color: silver; - color: silver; -} - - -/* ///////////////////////////////////////////////////////////////////////////// -named elements -///////////////////////////////////////////////////////////////////////////// */ - -#page { - min-width: 870px; - max-width: 1280px; -} - -#page h1 span { - display: none; -} - -#irc_info { - font-size: 8pt; - text-align: right; - height: 45px; - margin-top: 120px; - margin-right: 4px; -} - -#main_topleft { - background-image: url(images/layout/main_topleft.png); - background-position: top left; - background-repeat: no-repeat; -} - -#main_rightrepeat { - margin-left: 98px; - background-image: url(images/layout/main_rightrepeat.png); - background-position: right; - background-repeat: repeat-y; - - /* A one pixel padding to make IE render correctly - (the underscore is a hack to make only IE 5-6 see it) */ - _padding-bottom: 1px; -} - -#main_topright { - background-image: url(images/layout/main_topright.png); - background-position: top right; - background-repeat: no-repeat; -} - -#main_bottomright { - background-image: url(images/layout/main_bottomright.png); - background-position: bottom right; - background-repeat: no-repeat; -} - -#main { - padding: 0px 4px 0px 0px; -} - -#main .main_title_topright { - background-image: url(images/layout/main_title_topright.png); - background-position: top right; - background-repeat: no-repeat; - background-color: #f2ebe7; - margin: 0px 0px 20px 1px; -} - -#main .main_title_bottomright { - background-image: url(images/layout/main_title_bottomright.png); - background-position: bottom right; - background-repeat: no-repeat; - - /* A one pixel padding to make IE render correctly - (the underscore is a hack to make only IE 5-6 see it) */ - _padding-bottom: 1px; -} - -#main .main_title_topleft { - background-image: url(images/layout/main_title_topleft.png); - background-repeat: no-repeat; -} - -#main h2 { - padding: 7px 7px 7px 107px; - margin: 0px; - color: #57565c; - font-size: 16pt; -} - -#main h3 { - margin: 20px 0px 0px 0px; - font-weight: bold; - color: #3c3c3c; - border-bottom: 1px solid #9f9894; - font-size: 11pt; -} - -#main label { - background-color: #ede2da; - margin: 5px; - padding: 5px 5px 5px 15px; - white-space: nowrap; - font-weight: bold; - text-align: right; - -moz-border-radius: 10px; -} - -#main span.label { - background-color: #ede2da; - margin: 5px; - padding: 5px 5px 5px 15px; - white-space: nowrap; - font-weight: bold; - -moz-border-radius: 10px; -} - -#main span.input { - padding: 4px 10px 4px 10px; - margin: 5px; - color: #57565c; - font-size: 11pt; - background-color: #ede2da; - border: 1px solid #9f9894; - -moz-border-radius: 10px; -} - -#main input { - padding: 4px 10px 4px 10px; - margin: 5px; - color: #57565c; - font-size: 11pt; - background-color: #ede2da; - border: 1px solid #9f9894; - -moz-border-radius: 10px; -} - -#main select { - padding: 4px 10px 4px 10px; - margin: 5px; - color: #57565c; - font-size: 11pt; - background-color: #ede2da; - border: 1px solid #9f9894; - -moz-border-radius: 10px; -} - -/* ///////////////////////////////////////////////////////////////////////////// -sidebar -///////////////////////////////////////////////////////////////////////////// */ - -#sidebar { - border: 0px dashed red; - float: right; - width: 170px; - padding-top: 2px; -} - -#sidebar .section { - padding: 7px; -} - -#sidebar .section h3 { - text-align: center; - font-weight: bold; - font-size: 8pt; - margin: 0px 0px 50px 0px; - padding: 0px; - border-width: 0px; - color: #2f2e32; -} - -#sidebar .section_topleft { - margin: 10px; - background-image: url(images/layout/section_topleft.png); - background-position: top left; - background-repeat: no-repeat; - background-color: #cba083; - - /* A one pixel padding to make IE render correctly - (the underscore is a hack to make only IE 5-6 see it) */ - _padding-bottom: 1px; -} - -#sidebar .section_bottomleft { - background-image: url(images/layout/section_bottomleft.png); - background-position: bottom left; - background-repeat: no-repeat; -} - -#sidebar .section_topright { - background-image: url(images/layout/section_topright.png); - background-position: top right; - background-repeat: no-repeat; -} - -#sidebar .section_bottomright { - background-image: url(images/layout/section_bottomright.png); - background-position: bottom right; - background-repeat: no-repeat; -} - -#sidebar .section ul { - margin: 0px; - padding: 0px; -} - -#sidebar .section li { - list-style: none; - margin: 0px; -} - -#sidebar .section li a { - display: block; - margin: 0px; - width: auto; - border: 1px solid #cba083; - text-decoration: none; - padding: 5px 5px 5px 20px; - margin: 0px; - color: black; - font-style: normal; - font-weight: bold; - color: #2f2e32; - - /* Setting a background color fixes a strange hover issue with IE 7 */ - background-color: #cba083; -} - -#sidebar .section li a:hover { - border: 1px solid #78584c; - background-color: #dbbba4; -} - -/* ///////////////////////////////////////////////////////////////////////////// -style elements -///////////////////////////////////////////////////////////////////////////// */ - -img.online-led { - vertical-align: text-bottom; - padding: 0px 1px 0px 1px; -} - -/* ///////////////////////////////////////////////////////////////////////////// -contents -///////////////////////////////////////////////////////////////////////////// */ - -#contents_leftrepeat { - background-image: url(images/layout/contents_leftrepeat.png); - background-repeat: repeat-y; - background-color: #e1d6cf; - margin: 0px 170px 0px 0px; -} - -#contents_topleft { - background-image: url(images/layout/contents_topleft.png); - background-repeat: no-repeat; -} - -#contents_bottomleft { - background-image: url(images/layout/contents_bottomleft.png); - background-position: bottom left; - background-repeat: no-repeat; -} - -#contents_rightrepeat { - background-image: url(images/layout/contents_rightrepeat.png); - background-position: right; - background-repeat: repeat-y; -} - -#contents_topright { - background-image: url(images/layout/contents_topright.png); - background-position: top right; - background-repeat: no-repeat; -} - -#contents_bottomright { - background-image: url(images/layout/contents_bottomright.png); - background-position: bottom right; - background-repeat: no-repeat; -} - -#contents { - min-height: 400px; - padding: 12px 8px 250px 11px; - line-height: 150%; -} - -#contents p, table, pre { - margin: 15px 40px 15px 30px; -} - -#contents h4 { - margin-left: 30px; - margin-bottom: 0px; -} - -#contents ul { - margin: 15px 40px 13px 20px; - padding: 0px 0px 0px 40px; - list-style-image:url(images/icon16.png); -} - -#contents li { - padding-left: 5px; - margin-left: 0px; -} - -#contents table { - border-top: 1px solid #9f9894; - border-bottom: 1px solid #9f9894; -} - -#contents .datatable { - width: 95%; - padding: 4px 10px 4px 10px; - margin: 25px; - color: #57565c; - font-size: 11pt; - background-color: #ede2da; - border: 1px solid #9f9894; - -moz-border-radius: 10px; -} - -#contents td { - border-bottom: 1px dotted #9f9894; - padding: 3px 10px 3px 3px; -} - -#contents tr.last td { - border-width: 0px; -} - -#footer { - font-size: 8pt; - text-align: right; - padding: 5px; -} - -/* ///////////////////////////////////////////////////////////////////////////// -javascript features -///////////////////////////////////////////////////////////////////////////// */ - -#contents div.autocomplete { - margin: 3px 3px 3px 3px; - padding: 7px 7px 7px 7px; - width:250px; - background-color: #ede2da; - border: 1px solid #9f9894; - position:absolute; - -moz-border-radius: 10px; -} - -#contents div.autocomplete ul { - margin:0px; - padding:0px; - list-style-type:none; - list-style-image:none; -} - -#contents div.autocomplete ul li.selected { - background-color:#dbbba4; -} - -#contents div.autocomplete ul li { - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; - height:18px; - display:block; - list-style-type:none; - list-style-image:none; - cursor:pointer; - color:#57565c; -} - -/* ////////////////////// end of file /////////////////////////////////////// */ +/* ///////////////////////////////////////////////////////////////////////////// +basic elements +///////////////////////////////////////////////////////////////////////////// */ +body { + background-color: #eeeeee; + padding: 0px 10px 10px 10px; + margin: 0px; + font-family: sans-serif; +} + +body, div, p, td, li, h1, h2, h3, h4 { + font-family: sans-serif; + font-size: 10pt; +} + +h1 { + background-image: url(images/layout/header.png); + background-repeat: no-repeat; + position: absolute; + width: 600px; + height: 210px; + margin: 0px; + top: 0px; + border: 0px solid green; + z-index:200; +} + +a { + text-decoration: none; + color: rgb(100,10,10); +} + +a:visited { + color: rgb(60,0,0); +} + +a:hover { + text-decoration: underline; +} + +hr { + border-style: none; + height: 1px; + background-color: silver; + color: silver; +} + + +/* ///////////////////////////////////////////////////////////////////////////// +named elements +///////////////////////////////////////////////////////////////////////////// */ + +#page { + min-width: 870px; + max-width: 1280px; +} + +#page h1 span { + display: none; +} + +#irc_info { + font-size: 8pt; + text-align: right; + height: 45px; + margin-top: 120px; + margin-right: 4px; +} + +#main_topleft { + background-image: url(images/layout/main_topleft.png); + background-position: top left; + background-repeat: no-repeat; +} + +#main_rightrepeat { + margin-left: 98px; + background-image: url(images/layout/main_rightrepeat.png); + background-position: right; + background-repeat: repeat-y; + + /* A one pixel padding to make IE render correctly + (the underscore is a hack to make only IE 5-6 see it) */ + _padding-bottom: 1px; +} + +#main_topright { + background-image: url(images/layout/main_topright.png); + background-position: top right; + background-repeat: no-repeat; +} + +#main_bottomright { + background-image: url(images/layout/main_bottomright.png); + background-position: bottom right; + background-repeat: no-repeat; +} + +#main { + padding: 0px 4px 0px 0px; +} + +#main .main_title_topright { + background-image: url(images/layout/main_title_topright.png); + background-position: top right; + background-repeat: no-repeat; + background-color: #f2ebe7; + margin: 0px 0px 20px 1px; +} + +#main .main_title_bottomright { + background-image: url(images/layout/main_title_bottomright.png); + background-position: bottom right; + background-repeat: no-repeat; + + /* A one pixel padding to make IE render correctly + (the underscore is a hack to make only IE 5-6 see it) */ + _padding-bottom: 1px; +} + +#main .main_title_topleft { + background-image: url(images/layout/main_title_topleft.png); + background-repeat: no-repeat; +} + +#main h2 { + padding: 7px 7px 7px 107px; + margin: 0px; + color: #57565c; + font-size: 16pt; +} + +#main h3 { + margin: 20px 0px 0px 0px; + font-weight: bold; + color: #3c3c3c; + border-bottom: 1px solid #9f9894; + font-size: 11pt; +} + +#main label { + background-color: #ede2da; + margin: 5px; + padding: 5px 5px 5px 15px; + white-space: nowrap; + font-weight: bold; + text-align: right; + -moz-border-radius: 10px; +} + +#main span.label { + background-color: #ede2da; + margin: 5px; + padding: 5px 5px 5px 15px; + white-space: nowrap; + font-weight: bold; + -moz-border-radius: 10px; +} + +#main span.input { + padding: 4px 10px 4px 10px; + margin: 5px; + color: #57565c; + font-size: 11pt; + background-color: #ede2da; + border: 1px solid #9f9894; + -moz-border-radius: 10px; +} + +#main input { + padding: 4px 10px 4px 10px; + margin: 5px; + color: #57565c; + font-size: 11pt; + background-color: #ede2da; + border: 1px solid #9f9894; + -moz-border-radius: 10px; +} + +#main select { + padding: 4px 10px 4px 10px; + margin: 5px; + color: #57565c; + font-size: 11pt; + background-color: #ede2da; + border: 1px solid #9f9894; + -moz-border-radius: 10px; +} + +/* ///////////////////////////////////////////////////////////////////////////// +sidebar +///////////////////////////////////////////////////////////////////////////// */ + +#sidebar { + border: 0px dashed red; + float: right; + width: 170px; + padding-top: 2px; +} + +#sidebar .section { + padding: 7px; +} + +#sidebar .section h3 { + text-align: center; + font-weight: bold; + font-size: 8pt; + margin: 0px 0px 50px 0px; + padding: 0px; + border-width: 0px; + color: #2f2e32; +} + +#sidebar .section_topleft { + margin: 10px; + background-image: url(images/layout/section_topleft.png); + background-position: top left; + background-repeat: no-repeat; + background-color: #cba083; + + /* A one pixel padding to make IE render correctly + (the underscore is a hack to make only IE 5-6 see it) */ + _padding-bottom: 1px; +} + +#sidebar .section_bottomleft { + background-image: url(images/layout/section_bottomleft.png); + background-position: bottom left; + background-repeat: no-repeat; +} + +#sidebar .section_topright { + background-image: url(images/layout/section_topright.png); + background-position: top right; + background-repeat: no-repeat; +} + +#sidebar .section_bottomright { + background-image: url(images/layout/section_bottomright.png); + background-position: bottom right; + background-repeat: no-repeat; +} + +#sidebar .section ul { + margin: 0px; + padding: 0px; +} + +#sidebar .section li { + list-style: none; + margin: 0px; +} + +#sidebar .section li a { + display: block; + margin: 0px; + width: auto; + border: 1px solid #cba083; + text-decoration: none; + padding: 5px 5px 5px 20px; + margin: 0px; + color: black; + font-style: normal; + font-weight: bold; + color: #2f2e32; + + /* Setting a background color fixes a strange hover issue with IE 7 */ + background-color: #cba083; +} + +#sidebar .section li a:hover { + border: 1px solid #78584c; + background-color: #dbbba4; +} + +/* ///////////////////////////////////////////////////////////////////////////// +style elements +///////////////////////////////////////////////////////////////////////////// */ + +img.online-led { + vertical-align: text-bottom; + padding: 0px 1px 0px 1px; +} + +/* ///////////////////////////////////////////////////////////////////////////// +contents +///////////////////////////////////////////////////////////////////////////// */ + +#contents_leftrepeat { + background-image: url(images/layout/contents_leftrepeat.png); + background-repeat: repeat-y; + background-color: #e1d6cf; + margin: 0px 170px 0px 0px; +} + +#contents_topleft { + background-image: url(images/layout/contents_topleft.png); + background-repeat: no-repeat; +} + +#contents_bottomleft { + background-image: url(images/layout/contents_bottomleft.png); + background-position: bottom left; + background-repeat: no-repeat; +} + +#contents_rightrepeat { + background-image: url(images/layout/contents_rightrepeat.png); + background-position: right; + background-repeat: repeat-y; +} + +#contents_topright { + background-image: url(images/layout/contents_topright.png); + background-position: top right; + background-repeat: no-repeat; +} + +#contents_bottomright { + background-image: url(images/layout/contents_bottomright.png); + background-position: bottom right; + background-repeat: no-repeat; +} + +#contents { + min-height: 400px; + padding: 12px 8px 250px 11px; + line-height: 150%; +} + +#contents p, table, pre { + margin: 15px 40px 15px 30px; +} + +#contents h4 { + margin-left: 30px; + margin-bottom: 0px; +} + +#contents ul { + margin: 15px 40px 13px 20px; + padding: 0px 0px 0px 40px; + list-style-image:url(images/icon16.png); +} + +#contents li { + padding-left: 5px; + margin-left: 0px; +} + +#contents table { + border-top: 1px solid #9f9894; + border-bottom: 1px solid #9f9894; +} + +#contents .datatable { + width: 95%; + padding: 4px 10px 4px 10px; + margin: 25px; + color: #57565c; + font-size: 11pt; + background-color: #ede2da; + border: 1px solid #9f9894; + -moz-border-radius: 10px; +} + +#contents td { + border-bottom: 1px dotted #9f9894; + padding: 3px 10px 3px 3px; +} + +#contents tr.last td { + border-width: 0px; +} + +#footer { + font-size: 8pt; + text-align: right; + padding: 5px; +} + +/* ///////////////////////////////////////////////////////////////////////////// +javascript features +///////////////////////////////////////////////////////////////////////////// */ + +#contents div.autocomplete { + margin: 3px 3px 3px 3px; + padding: 7px 7px 7px 7px; + width:250px; + background-color: #ede2da; + border: 1px solid #9f9894; + position:absolute; + -moz-border-radius: 10px; +} + +#contents div.autocomplete ul { + margin:0px; + padding:0px; + list-style-type:none; + list-style-image:none; +} + +#contents div.autocomplete ul li.selected { + background-color:#dbbba4; +} + +#contents div.autocomplete ul li { + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + height:18px; + display:block; + list-style-type:none; + list-style-image:none; + cursor:pointer; + color:#57565c; +} + +/* ////////////////////// end of file /////////////////////////////////////// */ diff --git a/data/themes/tmw/theme.xml b/data/themes/tmw/theme.xml index 7450f4f..d249895 100644 --- a/data/themes/tmw/theme.xml +++ b/data/themes/tmw/theme.xml @@ -1,12 +1,12 @@ - - - - The Mana World - Andreas Habel - 1.0.0 - - tmwtheme.php - default.css - TMWTheme - - + + + + The Mana World + Andreas Habel + 1.0.0 + + tmwtheme.php + default.css + TMWTheme + + diff --git a/data/themes/tmw/tmwtheme.php b/data/themes/tmw/tmwtheme.php index 263b0cd..591d456 100644 --- a/data/themes/tmw/tmwtheme.php +++ b/data/themes/tmw/tmwtheme.php @@ -1,124 +1,124 @@ - - - - -
-

The Mana

-
"; - } - - public function beforeNavigationBar() - { - return "
-
-
- -
-
- -
-
"; - } - - public function afterNavigationBar() - { - return "
- -
- "; - } - - public function beforeNavigationBox() - { - return "
-
-
-
-
"; - } - - public function NavigationBox(NavigationBox $box) - { - $str = "
  • " .$box->getHeader() . "
  • "; - foreach( $box->getItems() as $item ) - { - $str .= sprintf("
  • %s
  • ", - $item->getUrl(), $item->getText() - ); - } - $str .= "
"; - return $str; - } - - public function afterNavigationBox() - { - return "
-
- -
-
-
-"; - } - - public function beforeContent() - { - return "
-
-
-
-
- -
-
"; - } - - public function afterContent() - { - return "
- -
-
-
-
-
-
-
- -
-
-
-
-
"; - - } - - public function title($string) - { - return "
-
-
-

" . $string . "

-
-
-
"; - - } -} - -?> + + + + +
+

The Mana

+
"; + } + + public function beforeNavigationBar() + { + return "
+
+
+ +
+
+ +
+
"; + } + + public function afterNavigationBar() + { + return "
+ +
+ "; + } + + public function beforeNavigationBox() + { + return "
+
+
+
+
"; + } + + public function NavigationBox(NavigationBox $box) + { + $str = "
  • " .$box->getHeader() . "
  • "; + foreach( $box->getItems() as $item ) + { + $str .= sprintf("
  • %s
  • ", + $item->getUrl(), $item->getText() + ); + } + $str .= "
"; + return $str; + } + + public function afterNavigationBox() + { + return "
+
+ +
+
+
+"; + } + + public function beforeContent() + { + return "
+
+
+
+
+ +
+
"; + } + + public function afterContent() + { + return "
+ +
+
+
+
+
+
+
+ +
+
+
+
+
"; + + } + + public function title($string) + { + return "
+
+
+

" . $string . "

+
+
+
"; + + } +} + +?> diff --git a/docs/Doxyfile b/docs/Doxyfile index aa9e4b0..811c7ad 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,263 +1,263 @@ -# Doxyfile 1.5.6 - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "The Mana Server Account Manager" -PROJECT_NUMBER = 1.0.0 -OUTPUT_DIRECTORY = ./docs -CREATE_SUBDIRS = YES -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = NO -STRIP_FROM_PATH = /var/www/webseiten/manaweb -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = YES -QT_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = NO -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 4 -ALIASES = "subpackage=\"\par Subpackage\n\"" \ - "link=\"\link {1} \endlink\n\"" \ - "subpackage=\ingroup {1}" \ - filesource= \ - "copyright=Copyright : {1}" \ - license= \ - access= -OPTIMIZE_OUTPUT_FOR_C = NO -OPTIMIZE_OUTPUT_JAVA = YES -OPTIMIZE_FOR_FORTRAN = NO -OPTIMIZE_OUTPUT_VHDL = NO -BUILTIN_STL_SUPPORT = NO -CPP_CLI_SUPPORT = NO -SIP_SUPPORT = NO -IDL_PROPERTY_SUPPORT = YES -DISTRIBUTE_GROUP_DOC = NO -SUBGROUPING = YES -TYPEDEF_HIDES_STRUCT = NO -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = NO -EXTRACT_PRIVATE = YES -EXTRACT_STATIC = YES -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = NO -EXTRACT_ANON_NSPACES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -SHOW_INCLUDE_FILES = YES -INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -SORT_BRIEF_DOCS = NO -SORT_GROUP_NAMES = NO -SORT_BY_SCOPE_NAME = NO -GENERATE_TODOLIST = YES -GENERATE_TESTLIST = YES -GENERATE_BUGLIST = YES -GENERATE_DEPRECATEDLIST= YES -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -SHOW_DIRECTORIES = YES -SHOW_FILES = YES -SHOW_NAMESPACES = YES -FILE_VERSION_FILTER = -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = YES -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = YES -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = warnings.txt -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = ./docs/doxyfile.php \ - ./system/application -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = *.php -RECURSIVE = YES -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = .svn -EXCLUDE_SYMBOLS = -EXAMPLE_PATH = README -EXAMPLE_PATTERNS = -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = NO -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES -USE_HTAGS = NO -VERBATIM_HEADERS = NO -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = YES -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = -HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES -GENERATE_HTMLHELP = NO -GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" -DOCSET_BUNDLE_ID = org.doxygen.Project -HTML_DYNAMIC_SECTIONS = YES -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -CHM_INDEX_ENCODING = -BINARY_TOC = NO -TOC_EXPAND = NO -DISABLE_INDEX = NO -ENUM_VALUES_PER_LINE = 4 -GENERATE_TREEVIEW = YES -TREEVIEW_WIDTH = 250 -FORMULA_FONTSIZE = 10 -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4wide -EXTRA_PACKAGES = -LATEX_HEADER = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -XML_PROGRAMLISTING = YES -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -PERL_PATH = /usr/bin/perl -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = YES -MSCGEN_PATH = -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = NO -DOT_FONTNAME = FreeSans -DOT_FONTPATH = -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = NO -TEMPLATE_RELATIONS = NO -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = NO -CALLER_GRAPH = NO -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -DOT_PATH = -DOTFILE_DIRS = -DOT_GRAPH_MAX_NODES = 50 -MAX_DOT_GRAPH_DEPTH = 1000 -DOT_TRANSPARENT = YES -DOT_MULTI_TARGETS = NO -GENERATE_LEGEND = YES -DOT_CLEANUP = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- -SEARCHENGINE = NO +# Doxyfile 1.5.6 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "The Mana Server Account Manager" +PROJECT_NUMBER = 1.0.0 +OUTPUT_DIRECTORY = ./docs +CREATE_SUBDIRS = YES +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = /var/www/webseiten/manaweb +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = "subpackage=\"\par Subpackage\n\"" \ + "link=\"\link {1} \endlink\n\"" \ + "subpackage=\ingroup {1}" \ + filesource= \ + "copyright=Copyright : {1}" \ + license= \ + access= +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = YES +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = warnings.txt +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ./docs/doxyfile.php \ + ./system/application +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.php +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = .svn +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = README +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = YES +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_FONTNAME = FreeSans +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/docs/doxyfile.php b/docs/doxyfile.php index 81d7b96..0673ea1 100644 --- a/docs/doxyfile.php +++ b/docs/doxyfile.php @@ -1,40 +1,40 @@ - \ No newline at end of file diff --git a/docs/make_docs.cmd b/docs/make_docs.cmd index 26fb4a5..50f708c 100644 --- a/docs/make_docs.cmd +++ b/docs/make_docs.cmd @@ -1,2 +1,2 @@ -cd .. -doxygen docs\Doxyfile +cd .. +doxygen docs\Doxyfile diff --git a/docs/make_docs.sh b/docs/make_docs.sh index 68d176f..ac9fa3a 100755 --- a/docs/make_docs.sh +++ b/docs/make_docs.sh @@ -1,3 +1,3 @@ -#!/bin/bash -cd .. -doxygen docs/Doxyfile +#!/bin/bash +cd .. +doxygen docs/Doxyfile diff --git a/ext/dhtml-suite-for-applications/js/ajax.js b/ext/dhtml-suite-for-applications/js/ajax.js index bb81898..d185c06 100755 --- a/ext/dhtml-suite-for-applications/js/ajax.js +++ b/ext/dhtml-suite-for-applications/js/ajax.js @@ -1,199 +1,199 @@ -/* Simple AJAX Code-Kit (SACK) v1.6.1 */ -/* ©2005 Gregory Wild-Smith */ -/* www.twilightuniverse.com */ -/* Software licenced under a modified X11 licence, - see documentation or authors website for more details */ - -function sack(file) { - this.xmlhttp = null; - - this.resetData = function() { - this.method = "POST"; - this.queryStringSeparator = "?"; - this.argumentSeparator = "&"; - this.URLString = ""; - this.encodeURIString = true; - this.execute = false; - this.element = null; - this.elementObj = null; - this.requestFile = file; - this.vars = new Object(); - this.responseStatus = new Array(2); - }; - - this.resetFunctions = function() { - this.onLoading = function() { }; - this.onLoaded = function() { }; - this.onInteractive = function() { }; - this.onCompletion = function() { }; - this.onError = function() { }; - this.onFail = function() { }; - }; - - this.reset = function() { - this.resetFunctions(); - this.resetData(); - }; - - this.createAJAX = function() { - try { - this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e1) { - try { - this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); - } catch (e2) { - this.xmlhttp = null; - } - } - - if (! this.xmlhttp) { - if (typeof XMLHttpRequest != "undefined") { - this.xmlhttp = new XMLHttpRequest(); - } else { - this.failed = true; - } - } - }; - - this.setVar = function(name, value){ - this.vars[name] = Array(value, false); - }; - - this.encVar = function(name, value, returnvars) { - if (true == returnvars) { - return Array(encodeURIComponent(name), encodeURIComponent(value)); - } else { - this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true); - } - } - - this.processURLString = function(string, encode) { - encoded = encodeURIComponent(this.argumentSeparator); - regexp = new RegExp(this.argumentSeparator + "|" + encoded); - varArray = string.split(regexp); - for (i = 0; i < varArray.length; i++){ - urlVars = varArray[i].split("="); - if (true == encode){ - this.encVar(urlVars[0], urlVars[1]); - } else { - this.setVar(urlVars[0], urlVars[1]); - } - } - } - - this.createURLString = function(urlstring) { - if (this.encodeURIString && this.URLString.length) { - this.processURLString(this.URLString, true); - } - - if (urlstring) { - if (this.URLString.length) { - this.URLString += this.argumentSeparator + urlstring; - } else { - this.URLString = urlstring; - } - } - - // prevents caching of URLString - this.setVar("rndval", new Date().getTime()); - - urlstringtemp = new Array(); - for (key in this.vars) { - if (false == this.vars[key][1] && true == this.encodeURIString) { - encoded = this.encVar(key, this.vars[key][0], true); - delete this.vars[key]; - this.vars[encoded[0]] = Array(encoded[1], true); - key = encoded[0]; - } - - urlstringtemp[urlstringtemp.length] = key + "=" + this.vars[key][0]; - } - if (urlstring){ - this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator); - } else { - this.URLString += urlstringtemp.join(this.argumentSeparator); - } - } - - this.runResponse = function() { - eval(this.response); - } - - this.runAJAX = function(urlstring) { - if (this.failed) { - this.onFail(); - } else { - this.createURLString(urlstring); - if (this.element) { - this.elementObj = document.getElementById(this.element); - } - if (this.xmlhttp) { - var self = this; - if (this.method == "GET") { - totalurlstring = this.requestFile + this.queryStringSeparator + this.URLString; - this.xmlhttp.open(this.method, totalurlstring, true); - } else { - this.xmlhttp.open(this.method, this.requestFile, true); - try { - this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") - } catch (e) { } - } - - this.xmlhttp.onreadystatechange = function() { - switch (self.xmlhttp.readyState) { - case 1: - self.onLoading(); - break; - case 2: - self.onLoaded(); - break; - case 3: - self.onInteractive(); - break; - case 4: - self.response = self.xmlhttp.responseText; - self.responseXML = self.xmlhttp.responseXML; - self.responseStatus[0] = self.xmlhttp.status; - self.responseStatus[1] = self.xmlhttp.statusText; - - if (self.execute) { - self.runResponse(); - } - - if (self.elementObj) { - elemNodeName = self.elementObj.nodeName; - elemNodeName = elemNodeName.toLowerCase(); - if (elemNodeName == "input" - || elemNodeName == "select" - || elemNodeName == "option" - || elemNodeName == "textarea") { - self.elementObj.value = self.response; - } else { - self.elementObj.innerHTML = self.response; - } - } - if (self.responseStatus[0] == "200") { - self.onCompletion(); - } else { - self.onError(); - } - /* These lines were added by Alf Magne Kalleland ref. info on the sack home page. It prevents memory leakage in IE */ - self.URLString = ""; - delete self.xmlhttp['onreadystatechange']; - self.xmlhttp=null; - self.responseStatus=null; - self.response=null; - self.responseXML=null; - - break; - } - }; - - this.xmlhttp.send(this.URLString); - } - } - }; - - this.reset(); - this.createAJAX(); -} +/* Simple AJAX Code-Kit (SACK) v1.6.1 */ +/* ©2005 Gregory Wild-Smith */ +/* www.twilightuniverse.com */ +/* Software licenced under a modified X11 licence, + see documentation or authors website for more details */ + +function sack(file) { + this.xmlhttp = null; + + this.resetData = function() { + this.method = "POST"; + this.queryStringSeparator = "?"; + this.argumentSeparator = "&"; + this.URLString = ""; + this.encodeURIString = true; + this.execute = false; + this.element = null; + this.elementObj = null; + this.requestFile = file; + this.vars = new Object(); + this.responseStatus = new Array(2); + }; + + this.resetFunctions = function() { + this.onLoading = function() { }; + this.onLoaded = function() { }; + this.onInteractive = function() { }; + this.onCompletion = function() { }; + this.onError = function() { }; + this.onFail = function() { }; + }; + + this.reset = function() { + this.resetFunctions(); + this.resetData(); + }; + + this.createAJAX = function() { + try { + this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); + } catch (e1) { + try { + this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + } catch (e2) { + this.xmlhttp = null; + } + } + + if (! this.xmlhttp) { + if (typeof XMLHttpRequest != "undefined") { + this.xmlhttp = new XMLHttpRequest(); + } else { + this.failed = true; + } + } + }; + + this.setVar = function(name, value){ + this.vars[name] = Array(value, false); + }; + + this.encVar = function(name, value, returnvars) { + if (true == returnvars) { + return Array(encodeURIComponent(name), encodeURIComponent(value)); + } else { + this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true); + } + } + + this.processURLString = function(string, encode) { + encoded = encodeURIComponent(this.argumentSeparator); + regexp = new RegExp(this.argumentSeparator + "|" + encoded); + varArray = string.split(regexp); + for (i = 0; i < varArray.length; i++){ + urlVars = varArray[i].split("="); + if (true == encode){ + this.encVar(urlVars[0], urlVars[1]); + } else { + this.setVar(urlVars[0], urlVars[1]); + } + } + } + + this.createURLString = function(urlstring) { + if (this.encodeURIString && this.URLString.length) { + this.processURLString(this.URLString, true); + } + + if (urlstring) { + if (this.URLString.length) { + this.URLString += this.argumentSeparator + urlstring; + } else { + this.URLString = urlstring; + } + } + + // prevents caching of URLString + this.setVar("rndval", new Date().getTime()); + + urlstringtemp = new Array(); + for (key in this.vars) { + if (false == this.vars[key][1] && true == this.encodeURIString) { + encoded = this.encVar(key, this.vars[key][0], true); + delete this.vars[key]; + this.vars[encoded[0]] = Array(encoded[1], true); + key = encoded[0]; + } + + urlstringtemp[urlstringtemp.length] = key + "=" + this.vars[key][0]; + } + if (urlstring){ + this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator); + } else { + this.URLString += urlstringtemp.join(this.argumentSeparator); + } + } + + this.runResponse = function() { + eval(this.response); + } + + this.runAJAX = function(urlstring) { + if (this.failed) { + this.onFail(); + } else { + this.createURLString(urlstring); + if (this.element) { + this.elementObj = document.getElementById(this.element); + } + if (this.xmlhttp) { + var self = this; + if (this.method == "GET") { + totalurlstring = this.requestFile + this.queryStringSeparator + this.URLString; + this.xmlhttp.open(this.method, totalurlstring, true); + } else { + this.xmlhttp.open(this.method, this.requestFile, true); + try { + this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") + } catch (e) { } + } + + this.xmlhttp.onreadystatechange = function() { + switch (self.xmlhttp.readyState) { + case 1: + self.onLoading(); + break; + case 2: + self.onLoaded(); + break; + case 3: + self.onInteractive(); + break; + case 4: + self.response = self.xmlhttp.responseText; + self.responseXML = self.xmlhttp.responseXML; + self.responseStatus[0] = self.xmlhttp.status; + self.responseStatus[1] = self.xmlhttp.statusText; + + if (self.execute) { + self.runResponse(); + } + + if (self.elementObj) { + elemNodeName = self.elementObj.nodeName; + elemNodeName = elemNodeName.toLowerCase(); + if (elemNodeName == "input" + || elemNodeName == "select" + || elemNodeName == "option" + || elemNodeName == "textarea") { + self.elementObj.value = self.response; + } else { + self.elementObj.innerHTML = self.response; + } + } + if (self.responseStatus[0] == "200") { + self.onCompletion(); + } else { + self.onError(); + } + /* These lines were added by Alf Magne Kalleland ref. info on the sack home page. It prevents memory leakage in IE */ + self.URLString = ""; + delete self.xmlhttp['onreadystatechange']; + self.xmlhttp=null; + self.responseStatus=null; + self.response=null; + self.responseXML=null; + + break; + } + }; + + this.xmlhttp.send(this.URLString); + } + } + }; + + this.reset(); + this.createAJAX(); +} diff --git a/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications-without-comments.js b/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications-without-comments.js index 03f01e4..a7f7af1 100755 --- a/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications-without-comments.js +++ b/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications-without-comments.js @@ -1,869 +1,869 @@ -if(!String.trim)String.prototype.trim=function(){return this.replace(/^\s+|\s+$/,'')};var DHTMLSuite_funcs=new Object();if(!window.DHTML_SUITE_THEME)var DHTML_SUITE_THEME='blue';if(!window.DHTML_SUITE_THEME_FOLDER)var DHTML_SUITE_THEME_FOLDER='../themes/';if(!window.DHTML_SUITE_JS_FOLDER)var DHTML_SUITE_JS_FOLDER='../js/separateFiles/';var DHTMLSuite=new Object();var standardObjectsCreated=false;DHTMLSuite.eventEls=new Array();var widgetDep=new Object();widgetDep['formValidator']=['dhtmlSuite-formUtil.js'];widgetDep['paneSplitter']=['dhtmlSuite-paneSplitter.js','dhtmlSuite-paneSplitterModel.js','dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['menuBar']=['dhtmlSuite-menuBar.js','dhtmlSuite-menuItem.js','dhtmlSuite-menuModel.js'];widgetDep['windowWidget']=['dhtmlSuite-windowWidget.js','dhtmlSuite-resize.js','dhtmlSuite-dragDropSimple.js','ajax.js','dhtmlSuite-dynamicContent.js'];widgetDep['colorWidget']=['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js'];widgetDep['colorSlider']=['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js','dhtmlSuite-slider.js'];widgetDep['colorPalette']=['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js'];widgetDep['calendar']=['dhtmlSuite-calendar.js','dhtmlSuite-dragDropSimple.js'];widgetDep['dragDropTree']=['dhtmlSuite-dragDropTree.js'];widgetDep['slider']=['dhtmlSuite-slider.js'];widgetDep['dragDrop']=['dhtmlSuite-dragDrop.js'];widgetDep['imageEnlarger']=['dhtmlSuite-imageEnlarger.js','dhtmlSuite-dragDropSimple.js'];widgetDep['imageSelection']=['dhtmlSuite-imageSelection.js'];widgetDep['floatingGallery']=['dhtmlSuite-floatingGallery.js','dhtmlSuite-mediaModel.js'];widgetDep['contextMenu']=['dhtmlSuite-contextMenu.js','dhtmlSuite-menuBar.js','dhtmlSuite-menuItem.js','dhtmlSuite-menuModel.js'];widgetDep['dynamicContent']=['dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['textEdit']=['dhtmlSuite-textEdit.js','dhtmlSuite-textEditModel.js','dhtmlSuite-listModel.js'];widgetDep['listModel']=['dhtmlSuite-listModel.js'];widgetDep['resize']=['dhtmlSuite-resize.js'];widgetDep['dragDropSimple']=['dhtmlSuite-dragDropSimple.js'];widgetDep['dynamicTooltip']=['dhtmlSuite-dynamicTooltip.js','dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['modalMessage']=['dhtmlSuite-modalMessage.js','dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['tableWidget']=['dhtmlSuite-tableWidget.js','ajax.js'];widgetDep['progressBar']=['dhtmlSuite-progressBar.js'];widgetDep['tabView']=['dhtmlSuite-tabView.js','dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['infoPanel']=['dhtmlSuite-infoPanel.js','dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['form']=['dhtmlSuite-formUtil.js','dhtmlSuite-dynamicContent.js','ajax.js'];widgetDep['autoComplete']=['dhtmlSuite-autoComplete.js','ajax.js'];widgetDep['chainedSelect']=['dhtmlSuite-chainedSelect.js','ajax.js'];var depCache=new Object();DHTMLSuite.include=function(widget){if(!widgetDep[widget]){alert('Cannot find the files for widget '+widget+'. Please verify that the name is correct');return} -var files=widgetDep[widget];for(var no=0;no');document.write('');depCache[files[no]]=true}}} -DHTMLSuite.discardElement=function(element){element=DHTMLSuite.commonObj.getEl(element);var gBin=document.getElementById('IELeakGBin');if(!gBin){gBin=document.createElement('DIV');gBin.id='IELeakGBin';gBin.style.display='none';document.body.appendChild(gBin)} -gBin.appendChild(element);gBin.innerHTML=''} -DHTMLSuite.createStandardObjects=function(){DHTMLSuite.clientInfoObj=new DHTMLSuite.clientInfo();DHTMLSuite.clientInfoObj.init();if(!DHTMLSuite.configObj){DHTMLSuite.configObj=new DHTMLSuite.config();DHTMLSuite.configObj.init()} -DHTMLSuite.commonObj=new DHTMLSuite.common();DHTMLSuite.variableStorage=new DHTMLSuite.globalVariableStorage();;DHTMLSuite.commonObj.init();DHTMLSuite.domQueryObj=new DHTMLSuite.domQuery();DHTMLSuite.commonObj.addEvent(window,'unload',function(){DHTMLSuite.commonObj.__clearMemoryGarbage()});standardObjectsCreated=true} -DHTMLSuite.config=function(){var imagePath;var cssPath;var defaultCssPath;var defaultImagePath} -DHTMLSuite.config.prototype={init:function(){this.imagePath=DHTML_SUITE_THEME_FOLDER+DHTML_SUITE_THEME+'/images/';this.cssPath=DHTML_SUITE_THEME_FOLDER+DHTML_SUITE_THEME+'/css/';this.defaultCssPath=this.cssPath;this.defaultImagePath=this.imagePath},setCssPath:function(newCssPath){this.cssPath=newCssPath},resetCssPath:function(){this.cssPath=this.defaultCssPath},resetImagePath:function(){this.imagePath=this.defaultImagePath},setImagePath:function(newImagePath){this.imagePath=newImagePath}} -DHTMLSuite.globalVariableStorage=function(){var menuBar_highlightedItems;this.menuBar_highlightedItems=new Array();var arrayDSObjects;var arrayOfDhtmlSuiteObjects;this.arrayDSObjects=new Array();this.arrayOfDhtmlSuiteObjects=this.arrayDSObjects;var ajaxObjects;this.ajaxObjects=new Array()} -DHTMLSuite.globalVariableStorage.prototype={} -DHTMLSuite.common=function(){var loadedCSSFiles;var cssCacheStatus;var eventEls;var isOkToSelect;this.okToSelect=true;this.cssCacheStatus=true;this.eventEls=new Array()} -DHTMLSuite.common.prototype={init:function(){this.loadedCSSFiles=new Array()},loadCSS:function(cssFile,prefixConfigPath){if(!prefixConfigPath&&prefixConfigPath!==false)prefixConfigPath=true;if(!this.loadedCSSFiles[cssFile]){this.loadedCSSFiles[cssFile]=true;var lt=document.createElement('LINK');if(!this.cssCacheStatus){if(cssFile.indexOf('?')>=0)cssFile=cssFile+'&';else cssFile=cssFile+'?';cssFile=cssFile+'rand='+Math.random()} -if(prefixConfigPath){lt.href=DHTMLSuite.configObj.cssPath+cssFile}else{lt.href=cssFile} -lt.rel='stylesheet';lt.media='screen';lt.type='text/css';document.getElementsByTagName('HEAD')[0].appendChild(lt)}},__setTextSelOk:function(okToSelect){this.okToSelect=okToSelect},__isTextSelOk:function(){return this.okToSelect},setCssCacheStatus:function(cssCacheStatus){this.cssCacheStatus=cssCacheStatus},getEl:function(elRef){if(typeof elRef=='string'){if(document.getElementById(elRef))return document.getElementById(elRef);if(document.forms[elRef])return document.forms[elRef];if(document[elRef])return document[elRef];if(window[elRef])return window[elRef]} -return elRef},isArray:function(el){if(el.constructor.toString().indexOf("Array")!=-1)return true;return false},getStyle:function(el,property){el=this.getEl(el);if(document.defaultView&&document.defaultView.getComputedStyle){var retVal=null;var comp=document.defaultView.getComputedStyle(el,'');if(comp){retVal=comp[property]} -return el.style[property]||retVal} -if(document.documentElement.currentStyle&&DHTMLSuite.clientInfoObj.isMSIE){var retVal=null;if(el.currentStyle)value=el.currentStyle[property];return(el.style[property]||retVal)} -return el.style[property]},getLeftPos:function(el){if(document.getBoxObjectFor){if(el.tagName!='INPUT'&&el.tagName!='SELECT'&&el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).x -} -var returnValue=el.offsetLeft;while((el=el.offsetParent)!=null){if(el.tagName!='HTML'){returnValue+= el.offsetLeft;if(document.all)returnValue+=el.clientLeft}} -return returnValue},getTopPos:function(el){if(document.getBoxObjectFor){if(el.tagName!='INPUT'&&el.tagName!='SELECT'&&el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).y -} -var returnValue=el.offsetTop;while((el=el.offsetParent)!=null){if(el.tagName!='HTML'){returnValue+=(el.offsetTop-el.scrollTop);if(document.all)returnValue+=el.clientTop}} -return returnValue},getCookie:function(name){var start=document.cookie.indexOf(name+"=");var len=start+name.length+1;if((!start)&&(name!=document.cookie.substring(0,name.length)))return null;if(start==-1)return null;var end=document.cookie.indexOf(";",len);if(end==-1)end=document.cookie.length;return unescape(document.cookie.substring(len,end))},setCookie:function(name,value,expires,path,domain,secure){expires=expires*60*60*24*1000;var today=new Date();var expires_date=new Date(today.getTime()+(expires));var cookieString=name+"="+escape(value)+ -((expires)?";expires="+expires_date.toGMTString():"")+ -((path)?";path="+path:"")+ -((domain)?";domain="+domain:"")+ -((secure)?";secure":"");document.cookie=cookieString},deleteCookie:function(name,path,domain){if(this.getCookie(name))document.cookie=name+"="+ -((path)?";path="+path:"")+ -((domain)?";domain="+domain:"")+ -";expires=Thu,01-Jan-1970 00:00:01 GMT"},cancelEvent:function(){return false},addEvent:function(obj,type,fn,suffix){if(!suffix)suffix='';if(obj.attachEvent){if(typeof DHTMLSuite_funcs[type+fn+suffix]!='function'){DHTMLSuite_funcs[type+fn+suffix]=function(){fn.apply(window.event.srcElement)};obj.attachEvent('on'+type,DHTMLSuite_funcs[type+fn+suffix])} -obj=null} else {obj.addEventListener(type,fn,false)} -this.__addEventEl(obj)},removeEvent:function(obj,type,fn,suffix){if(obj.detachEvent){obj.detachEvent('on'+type,DHTMLSuite_funcs[type+fn+suffix]);DHTMLSuite_funcs[type+fn+suffix]=null;obj=null} else {obj.removeEventListener(type,fn,false)}},__clearMemoryGarbage:function(){if(!DHTMLSuite.clientInfoObj.isMSIE)return;for(var no=0;no';img.outerHTML=html},__evaluateJs:function(obj){obj=this.getEl(obj);var scriptTags=obj.getElementsByTagName('SCRIPT');var string='';var jsCode='';for(var no=0;no=0)?true:false;this.isFirefox=(this.browser.toLowerCase().indexOf('firefox')>=0)?true:false;this.isMSIE=(this.browser.toLowerCase().indexOf('msie')>=0)?true:false;this.isOldMSIE=(this.browser.toLowerCase().match(/msie\s[0-6]/gi))?true:false;this.isSafari=(this.browser.toLowerCase().indexOf('safari')>=0)?true:false;this.navigatorVersion=navigator.appVersion.replace(/.*?MSIE\s(\d\.\d).*/g,'$1')/1;this.isOldMSIE=(this.isMSIE&&this.navigatorVersion<7)?true:false},getBrowserWidth:function(){if(self.innerWidth)return self.innerWidth;return document.documentElement.offsetWidth},getBrowserHeight:function(){if(self.innerHeight)return self.innerHeight;return document.documentElement.offsetHeight}} -DHTMLSuite.domQuery=function(){document.getElementsByClassName=this.getElementsByClassName;document.getElementsByAttribute=this.getElementsByAttribute} -DHTMLSuite.domQuery.prototype={} -DHTMLSuite.tableWidgetPageHandler=function(){var tableRef;var targetRef;var txtPrevious;var txtNext;var txtFirst;var txtLast;var txtResultPrefix;var txtResultTo;var txtResultOf;var totalNumberOfRows;var rowsPerPage;var layoutCSS;var activePageNumber;var mainDivEl;var resultDivElement;var pageListDivEl;var objectIndex;var linkPagePrefix;var linkPageSuffix;var maximumNumberOfPageLinks;var callbackOnAfterNavigate;this.txtPrevious='Previous';this.txtNext='Next';this.txtResultPrefix='Result: ';this.txtResultTo='to';this.txtResultOf='of';this.txtFirst='First';this.txtLast='Last';this.tableRef=false;this.targetRef=false;this.totalNumberOfRows=false;this.activePageNumber=0;this.layoutCSS='table-widget-page-handler.css';this.linkPagePrefix='';this.linkPageSuffix='';this.maximumNumberOfPageLinks=false;this.callbackOnAfterNavigate=false;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} -DHTMLSuite.tableWidgetPageHandler.prototype={setTableRef:function(tableRef){this.tableRef=tableRef;this.tableRef.setPageHandler(this)},setTargetId:function(idOfHTMLElement){if(!document.getElementById(idOfHTMLElement)){alert('ERROR IN tableWidgetPageHandler.setTargetId:\nElement with id '+idOfHTMLElement+' does not exists');return} -this.targetRef=document.getElementById(idOfHTMLElement)},setTxtPrevious:function(newText){this.txtPrevious=newText},setLinkPagePrefix:function(linkPagePrefix){this.linkPagePrefix=linkPagePrefix},setLinkPageSuffix:function(linkPageSuffix){this.linkPageSuffix=linkPageSuffix},setTxtNext:function(newText){this.txtNext=newText},setTxtResultOf:function(txtResultOf){this.txtResultOf=txtResultOf},setTxtResultTo:function(txtResultTo){this.txtResultTo=txtResultTo},setTxtResultPrefix:function(txtResultPrefix){this.txtResultPrefix=txtResultPrefix},setTxtFirstPage:function(txtFirst){this.txtFirst=txtFirst},setTxtLastPage:function(txtLast){this.txtLast=txtLast},setTotalNumberOfRows:function(totalNumberOfRows){this.totalNumberOfRows=totalNumberOfRows},setCallbackOnAfterNavigate:function(callbackOnAfterNavigate){this.callbackOnAfterNavigate=callbackOnAfterNavigate},setLayoutCss:function(layoutCSS){this.layoutCSS=layoutCSS},setMaximumNumberOfPageLinks:function(maximumNumberOfPageLinks){this.maximumNumberOfPageLinks=maximumNumberOfPageLinks},init:function(){this.rowsPerPage=this.tableRef.getServersideSortNumberOfRows();DHTMLSuite.commonObj.loadCSS(this.layoutCSS);this.__createMainDivEls();this.setHTMLOfResultList();this.__createPageLinks();this.goToPage(1)},__createMainDivEls:function(){if(!this.targetRef){alert('Error creating table widget page handler. Remember to specify targetRef');return} -this.mainDivEl=document.createElement('DIV');this.mainDivEl.className='DHTMLSuite_tableWidgetPageHandler_mainDiv';this.targetRef.appendChild(this.mainDivEl);this.resultDivElement=document.createElement('DIV');this.resultDivElement.className='DHTMLSuite_tableWidgetPageHandler_result';this.mainDivEl.appendChild(this.resultDivElement);this.pageListDivEl=document.createElement('DIV');this.pageListDivEl.className='DHTMLSuite_tableWidgetPageHandler_pageList';this.mainDivEl.appendChild(this.pageListDivEl)},setHTMLOfResultList:function(){this.resultDivElement.innerHTML='';var html=this.txtResultPrefix+(((this.activePageNumber-1)*this.rowsPerPage)+1)+' '+this.txtResultTo+' '+Math.min(this.totalNumberOfRows,(this.activePageNumber*this.rowsPerPage))+' '+this.txtResultOf+' '+this.totalNumberOfRows;this.resultDivElement.innerHTML=html},__createPageLinks:function(){var ind=this.objectIndex;this.pageListDivEl.innerHTML='';var numberOfPages=Math.ceil(this.totalNumberOfRows/this.rowsPerPage);if(this.maximumNumberOfPageLinks&&this.maximumNumberOfPageLinks=0){var pageNo=src.id.replace(/[^0-9]/gi,'')/1;this.activePageNumber=pageNo} -if(src.id=='next'){this.activePageNumber++;if(this.activePageNumber>numberOfPages)this.activePageNumber=numberOfPages} -if(src.id=='previous'){this.activePageNumber--;if(this.activePageNumber<1)this.activePageNumber=1} -if(this.activePageNumber!=initActivePageNumber){this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage);this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate);this.setHTMLOfResultList();this.__createPageLinks()} -return false},__resetActivePageNumber:function(){this.activePageNumber=1;this.setHTMLOfResultList();this.__createPageLinks()},goToPage:function(pageNo){var initActivePageNumber=this.activePageNumber;this.activePageNumber=pageNo;if(this.activePageNumber!=initActivePageNumber){this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage);this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate);this.setHTMLOfResultList();this.__createPageLinks()}}} -DHTMLSuite.tableWidget=function(){var tableWidget_okToSort;var activeColumn;var idOfTable;var tableObj;var widthOfTable;var heightOfTable;var columnSortArray;var layoutCSS;var noCssLayout;var serversideSort;var serversideSortAscending;var tableCurrentlySortedBy;var serversideSortFileName;var serversideSortNumberOfRows;var serversideSortCurrentStartIndex;var serversideSortExtraSearchCriterias;var pageHandler;var rowClickCallBackFunction;var objectIndex;this.serversideSort=false;this.serversideSortAscending=true;this.tableCurrentlySortedBy=false;this.serversideSortFileName=false;this.serversideSortCurrentStartIndex=0;this.serversideSortExtraSearchCriterias='';this.rowClickCallBackFunction=false;this.setRowDblClickCallBackFunction=false;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} -this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} -DHTMLSuite.tableWidget.prototype={init:function(){this.tableWidget_okToSort=true;this.activeColumn=false;if(!this.layoutCSS)this.layoutCSS='table-widget.css';DHTMLSuite.commonObj.loadCSS(this.layoutCSS);this.__initTableWidget()},setLayoutCss:function(newCssFile){this.layoutCSS=newCssFile},setRowClickCallBack:function(rowClickCallBackFunction){this.rowClickCallBackFunction=rowClickCallBackFunction},setRowDblClickCallBack:function(setRowDblClickCallBackFunction){this.setRowDblClickCallBackFunction=setRowDblClickCallBackFunction},setServerSideSort:function(serversideSort){this.serversideSort=serversideSort},setServersideSearchCriterias:function(serversideSortExtraSearchCriterias){this.serversideSortExtraSearchCriterias=serversideSortExtraSearchCriterias},getServersideSortNumberOfRows:function(serversideSort){return this.serversideSortNumberOfRows},setServersideSortNumberOfRows:function(serversideSortNumberOfRows){this.serversideSortNumberOfRows=serversideSortNumberOfRows},setServersideSortFileName:function(serversideSortFileName){this.serversideSortFileName=serversideSortFileName},setNoCssLayout:function(){this.noCssLayout=true},sortTableByColumn:function(columnIndex,howToSort){if(!howToSort)howToSort='ascending';var tableObj=document.getElementById(this.idOfTable);var firstRow=tableObj.rows[0];var tds=firstRow.cells;if(tds[columnIndex]&&this.columnSortArray[columnIndex]){this.__sortTable(tds[columnIndex],howToSort)}},setTableId:function(idOfTable){this.idOfTable=idOfTable;try{this.tableObj=document.getElementById(idOfTable)}catch(e){}},setTableWidth:function(width){this.widthOfTable=width},setTableHeight:function(height){this.heightOfTable=height},setColumnSort:function(columnSortArray){this.columnSortArray=columnSortArray},addNewRow:function(cellContent){var tObj=document.getElementById(this.idOfTable);var tb=tObj.getElementsByTagName('TBODY')[0];var row=tb.insertRow(-1);for(var no=0;no=0){obj.style.width='100%';obj.parentNode.style.width=this.widthOfTable}else{obj.style.width=this.widthOfTable+'px';obj.parentNode.style.width=this.widthOfTable+'px'} -if(this.heightOfTable.indexOf('%')>=0){obj.parentNode.style.height=this.heightOfTable}else{obj.parentNode.style.height=this.heightOfTable+'px'}} -if(!DHTMLSuite.clientInfoObj.isMSIE){this.__addEndCol(obj)}else{obj.style.cssText='width:expression(this.parentNode.clientWidth)'} -obj.cellSpacing=0;obj.cellPadding=0;if(!this.noCssLayout)obj.className='DHTMLSuite_tableWidget';var tHead=obj.getElementsByTagName('THEAD')[0];var cells=tHead.getElementsByTagName('TD');var tBody=obj.getElementsByTagName('TBODY')[0];tBody.className='DHTMLSuite_scrollingContent';for(var no=0;no=0){obj.parentNode.style.overflow='auto'}}} -this.__parseDataRows(obj);var ind=this.objectIndex},__addEndCol:function(obj){var rows=obj.getElementsByTagName('TR');for(var no=0;no';cell.style.width='13px';cell.width='13';cell.style.overflow='hidden'}},__highlightTableHeader:function(){this.className='DHTMLSuite_tableWigdet_headerCellOver';if(document.all){var divObj=this.parentNode.parentNode.parentNode.parentNode;this.parentNode.style.top=divObj.scrollTop+'px'}},__removeHighlightEffectFromTableHeader:function(){this.className='DHTMLSuite_tableWidget_headerCell'},__mousedownOnTableHeader:function(){this.className='DHTMLSuite_tableWigdet_headerCellDown';if(document.all){var divObj=this.parentNode.parentNode.parentNode.parentNode;this.parentNode.style.top=divObj.scrollTop+'px'}},__sortNumeric:function(a,b){a=a.replace(/,/,'.');b=b.replace(/,/,'.');a=a.replace(/[^\d\.\/]/g,'');b=b.replace(/[^\d\.\/]/g,'');if(a.indexOf('/')>=0)a=eval(a);if(b.indexOf('/')>=0)b=eval(b);return a/1-b/1},__sortString:function(a,b){if(a.toUpperCase()< b.toUpperCase())return-1;if(a.toUpperCase()> b.toUpperCase())return 1;return 0},__parseDataContentFromServer:function(ajaxIndex){var content=DHTMLSuite.variableStorage.ajaxObjects[ajaxIndex].response;if(content.indexOf('|||')==-1&&content.indexOf('###')==-1){alert('Error in data from server\n'+content);return} -this.__clearDataRows();var rows=content.split('|||');for(var no=0;no1)this.__fillDataRow(items)} -this.__parseDataRows(this.tableObj)},__clearDataRows:function(){if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable);while(this.tableObj.rows.length>1){DHTMLSuite.discardElement(this.tableObj.rows[this.tableObj.rows.length-1])}},__fillDataRow:function(data){if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable);var tbody=this.tableObj.getElementsByTagName('TBODY')[0];var row=tbody.insertRow(-1);for(var no=0;no 0) -sembol='&';var url=this.serversideSortFileName+sembol+'sortBy='+this.tableCurrentlySortedBy+'&numberOfRows='+this.serversideSortNumberOfRows+'&sortAscending='+this.serversideSortAscending+'&startIndex='+this.serversideSortCurrentStartIndex+this.serversideSortExtraSearchCriterias;var index=DHTMLSuite.variableStorage.ajaxObjects.length;try{DHTMLSuite.variableStorage.ajaxObjects[index]=new sack()}catch(e){alert('Unable to create ajax object. Please make sure that the sack js file is included on your page(js/ajax.js)');return} -DHTMLSuite.variableStorage.ajaxObjects[index].requestFile=url;DHTMLSuite.variableStorage.ajaxObjects[index].onCompletion=function(){DHTMLSuite.variableStorage.arrayDSObjects[objIndex].__parseDataContentFromServer(index);eval(callbackFunction)};DHTMLSuite.variableStorage.ajaxObjects[index].runAJAX()},__sortTable:function(obj,howToSort){if(this.serversideSort){if(!this.serversideSortFileName){alert('No server side file defined. Use the setServersideSortFileName to specify where to send the ajax request');return} -var sortBy=obj.getAttribute('sortBy');if(!sortBy)sortBy=obj.sortBy;if(!sortBy){alert('Sort is not defined. Remember to set a sortBy attribute on the header tags');return} -if(sortBy==this.tableCurrentlySortedBy)this.serversideSortAscending=!this.serversideSortAscending;else this.serversideSortAscending=true;if(howToSort)this.serversideSortAscending=(howToSort=='ascending'?true:false);this.tableCurrentlySortedBy=sortBy;this.serversideSortCurrentStartIndex =0;this.__getItemsFromServer();if(this.pageHandler)this.pageHandler.__resetActivePageNumber();this.__updateSortArrow(obj,this.serversideSortAscending?'ascending':'descending');return} -if(!this.tableWidget_okToSort)return;this.tableWidget_okToSort=false;var indexThis=0;var tmpObj=obj;while(tmpObj.previousSibling){tmpObj=tmpObj.previousSibling;if(tmpObj.tagName=='TD')indexThis++} -if(obj.getAttribute('direction')||obj.direction){direction=obj.getAttribute('direction');if(navigator.userAgent.indexOf('Opera')>=0)direction=obj.direction;if(direction=='ascending'||howToSort=='descending'){direction='descending';obj.setAttribute('direction','descending');obj.direction='descending'}else{direction='ascending';obj.setAttribute('direction','ascending');obj.direction='ascending'}}else{var curDir='ascending';if(howToSort)curDir=howToSort;direction=curDir;obj.setAttribute('direction',curDir);obj.direction=curDir} -this.__updateSortArrow(obj,direction);var tableObj=obj.parentNode.parentNode.parentNode;var tBody=tableObj.getElementsByTagName('TBODY')[0];var widgetIndex=tableObj.id.replace(/[^\d]/g,'');var sortMethod=this.columnSortArray[indexThis];var cellArray=new Array();var cellObjArray=new Array();for(var no=1;no=0;no--){for(var no2=0;no2DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=this.divElement.style.zIndex/1;DHTMLSuite_dragDropSimple_curZIndex=DHTMLSuite_dragDropSimple_curZIndex/1+1;this.divElement.style.zIndex=DHTMLSuite_dragDropSimple_curZIndex;if(this.cloneNode){var copy=this.divElement.cloneNode(true);this.divElement.parentNode.insertBefore(copy,this.divElement);copy.style.visibility='hidden';document.body.appendChild(this.divElement)} -DHTMLSuite.commonObj.addEvent(this.divElement,'mousedown',function(e){DHTMLSuite.variableStorage.arrayDSObjects[ind].__initDragProcess(e)},ind);DHTMLSuite.commonObj.addEvent(document.documentElement,'mousemove',function(e){DHTMLSuite.variableStorage.arrayDSObjects[ind].__moveDragableElement(e)},ind);DHTMLSuite.commonObj.addEvent(document.documentElement,'mouseup',function(e){DHTMLSuite.variableStorage.arrayDSObjects[ind].__stopDragProcess(e)},ind);if(!document.documentElement.onselectstart)document.documentElement.onselectstart=function(){return DHTMLSuite.commonObj.__isTextSelOk()}},setCallbackOnAfterDrag:function(functionName){this.callbackOnAfterDrag=functionName},setCallbackOnBeforeDrag:function(functionName){this.callbackOnBeforeDrag=functionName},addDragHandle:function(dragHandle){this.dragHandle[this.dragHandle.length]=dragHandle},__initDragProcess:function(e){if(document.all)e=event;var ind=this.objectIndex;DHTMLSuite_dragDropSimple_curObjIndex=ind;var thisObject=DHTMLSuite.variableStorage.arrayDSObjects[ind];if(!DHTMLSuite.commonObj.isObjectClicked(thisObject.divElement,e))return;if(thisObject.divElement.style.zIndex&&thisObject.divElement.style.zIndex/1>DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=thisObject.divElement.style.zIndex/1;DHTMLSuite_dragDropSimple_curZIndex=DHTMLSuite_dragDropSimple_curZIndex/1+1;thisObject.divElement.style.zIndex=DHTMLSuite_dragDropSimple_curZIndex;if(thisObject.callbackOnBeforeDrag){thisObject.__handleCallback('beforeDrag',e)} -if(thisObject.dragHandle.length>0){var objectFound;for(var no=0;no=0&&this.dragTimer<5){this.dragTimer++;setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+ind+'].__waitBeforeDragProcessStarts()',5)}},__moveDragableElement:function(e){if(document.all)e=event;var ind=this.objectIndex;var thisObj=DHTMLSuite.variableStorage.arrayDSObjects[ind];if(DHTMLSuite.clientInfoObj.isMSIE&&e.button!=1)return thisObj.__stopDragProcess();if(thisObj.dragTimer==5){if(thisObj.allowMoveX){var leftPos=(e.clientX-this.mouse_x+this.el_x);if(this.maxX!==false){if(leftPos+document.documentElement.scrollLeft>this.initialXPos+this.maxX){leftPos=this.initialXPos+this.maxX}} -if(this.minX!==false){if(leftPos+document.documentElement.scrollLeftthis.initialYPos+this.maxY){topPos=this.initialYPos+this.maxY}} -if(this.minY!==false){if(topPos DHTMLSuite_dragDropSimple_curZIndex){DHTMLSuite_dragDropSimple_curZIndex=zIndex/1+1}}} -DHTMLSuite.dragDrop=function(){var mouse_x;var mouse_y;var el_x;var el_y;var dragDropTimer;var numericIdToBeDragged;var dragObjCloneArray;var dragDropSourcesArray;var dragDropTargetArray;var currentZIndex;var okToStartDrag;var moveBackBySliding;var dragX_allowed;var dragY_allowed;var currentEl_allowX;var currentEl_allowY;var drag_minX;var drag_maxX;var drag_minY;var drag_maxY;var dragInProgress;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} -this.dragX_allowed=true;this.dragY_allowed=true;this.currentZIndex=21000;this.dragDropTimer=-1;this.dragObjCloneArray=new Array();this.numericIdToBeDragged=false;this.okToStartDrag=true;this.moveBackBySliding=true;this.dragInProgress=false;var objectIndex;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} -DHTMLSuite.dragDrop.prototype={init:function(){this.__initDragDropScript()},addSource:function(sourceId,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId){if(!this.dragDropSourcesArray)this.dragDropSourcesArray=new Array();if(!document.getElementById(sourceId)){alert('The source element with id '+sourceId+' does not exists. Check your HTML code');return} -if(xAxis!==false)xAxis=true;if(yAxis!==false)yAxis=true;var obj=document.getElementById(sourceId);this.dragDropSourcesArray[this.dragDropSourcesArray.length] =[obj,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId];obj.setAttribute('dragableElement',this.dragDropSourcesArray.length-1);obj.dragableElement=this.dragDropSourcesArray.length-1},addTarget:function(targetId,functionToCallOnDrop){if(!this.dragDropTargetArray)this.dragDropTargetArray=new Array();if(!document.getElementById(targetId))alert('The target element with id '+targetId+' does not exists. Check your HTML code');var obj=document.getElementById(targetId);this.dragDropTargetArray[this.dragDropTargetArray.length] =[obj,functionToCallOnDrop]},setSlide:function(isSlidingAnimationEnabled){this.moveBackBySliding=isSlidingAnimationEnabled},__initDragDropScript:function(){var ind=this.objectIndex;var refToThis=this;var startIndex=Math.random()+'';startIndex=startIndex.replace('.','')/1;for(var no=0;no=0&&this.dragDropTimer<5){this.dragDropTimer=this.dragDropTimer+1;setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+ind+'].__waitBeforeDragProcessStarts()',2);return} -if(this.dragDropTimer>=5){if(this.dragObjCloneArray[this.numericIdToBeDragged].style.display=='none'){this.dragDropSourcesArray[this.numericIdToBeDragged][0].style.visibility='hidden';var ref=this.dragObjCloneArray[this.numericIdToBeDragged];ref.style.display='block';ref.style.visibility='visible';ref.style.top=DHTMLSuite.commonObj.getTopPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0])+'px';ref.style.left=DHTMLSuite.commonObj.getLeftPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0])+'px'}}},__moveDragableElement:function(e){var ind=this.objectIndex;if(document.all)e=event;if(this.dragDropTimer<5)return false;if(this.dragInProgress)return false;this.dragInProgress=true;var dragObj=this.dragObjCloneArray[this.numericIdToBeDragged];if(this.currentEl_allowX){var leftPos=(e.clientX-this.mouse_x+this.el_x);if(this.drag_maxX){var tmpMaxX=this.drag_maxX-dragObj.offsetWidth;if(leftPos > tmpMaxX)leftPos=tmpMaxX -if(leftPos < this.drag_minX)leftPos=this.drag_minX} -dragObj.style.left=leftPos+'px'} -if(this.currentEl_allowY){var topPos=(e.clientY-this.mouse_y+this.el_y);if(this.drag_maxY){var tmpMaxY=this.drag_maxY-dragObj.offsetHeight;if(topPos > tmpMaxY)topPos=tmpMaxY;if(topPos < this.drag_minY)topPos=this.drag_minY} -dragObj.style.top=topPos+'px'} -this.dragInProgress=false;return false},__stopDragProcess:function(e){if(this.dragDropTimer<5)return false;if(document.all)e=event;var dropDestination=DHTMLSuite.commonObj.getSrcElement(e);var leftPosMouse=e.clientX+Math.max(document.body.scrollLeft,document.documentElement.scrollLeft);var topPosMouse=e.clientY+Math.max(document.body.scrollTop,document.documentElement.scrollTop);if(!this.dragDropTargetArray)this.dragDropTargetArray=new Array();for(var no=0;no leftPosEl&&leftPosMouse <(leftPosEl+widthEl)&&topPosMouse > topPosEl&&topPosMouse <(topPosEl+heightEl)){if(this.dragDropTargetArray[no][1]){try{eval(this.dragDropTargetArray[no][1]+'("'+this.dragDropSourcesArray[this.numericIdToBeDragged][0].id+'","'+this.dragDropTargetArray[no][0].id+'",'+e.clientX+','+e.clientY+')')}catch(e){alert('Unable to execute \n'+this.dragDropTargetArray[no][1]+'("'+this.dragDropSourcesArray[this.numericIdToBeDragged][0].id+'","'+this.dragDropTargetArray[no][0].id+'",'+e.clientX+','+e.clientY+')')}} -break}} -if(this.dragDropSourcesArray[this.numericIdToBeDragged][1]){this.__slideElementBackIntoItsOriginalPosition(this.numericIdToBeDragged)} -this.dragDropTimer=-1;DHTMLSuite.commonObj.__setTextSelOk(true);this.numericIdToBeDragged=false},__slideElementBackIntoItsOriginalPosition:function(numId){var currentX=this.dragObjCloneArray[numId].style.left.replace('px','')/1;var currentY=this.dragObjCloneArray[numId].style.top.replace('px','')/1;var ref=this.dragDropSourcesArray[numId][0];var targetX=DHTMLSuite.commonObj.getLeftPos(ref);var targetY=DHTMLSuite.commonObj.getTopPos(ref);;if(this.moveBackBySliding){this.__processSlideByPixels(numId,currentX,currentY,targetX,targetY)}else{this.dragObjCloneArray[numId].style.display='none';ref.style.visibility='visible'}},__processSlideByPixels:function(numId,currentX,currentY,targetX,targetY){var slideX=Math.round(Math.abs(Math.max(currentX,targetX)- Math.min(currentX,targetX))/10);var slideY=Math.round(Math.abs(Math.max(currentY,targetY)- Math.min(currentY,targetY))/10);if(slideY<3&&Math.abs(slideX)<10)slideY=3;if(slideX<3&&Math.abs(slideY)<10)slideX=3;if(currentX > targetX)slideX*=-1;if(currentY > targetY)slideY*=-1;currentX=currentX+slideX;currentY=currentY+slideY;if(Math.max(currentX,targetX)- Math.min(currentX,targetX)< 4)currentX=targetX;if(Math.max(currentY,targetY)- Math.min(currentY,targetY)< 4)currentY=targetY;this.dragObjCloneArray[numId].style.left=currentX+'px';this.dragObjCloneArray[numId].style.top=currentY+'px';if(currentX!=targetX||currentY!=targetY){window.thisRef=this;setTimeout('window.thisRef.__processSlideByPixels("'+numId+'",'+currentX+','+currentY+','+targetX+','+targetY+')',5)}else{this.dragObjCloneArray[numId].style.display='none';this.dragDropSourcesArray[numId][0].style.visibility='visible'}}} -if(!window.DHTMLSuite)var DHTMLSuite=new Object();/************************************************************************************************************ -*Tab view class -* -*Created:August,21st,2006 -* -*Update log:* -************************************************************************************************************/ -var refToTabViewObjects=new Array();DHTMLSuite.tabView=function(){var textPadding;var strictDocType ;var DHTMLSuite_tabObj;var activeTabIndex;var initActiveTabIndex;var ajaxObjects;var tabView_countTabs;var tabViewHeight;var tabSetParentId;var tabTitles;var width;var height;var layoutCSS;var outsideObjectRefIndex;var maxNumberOfTabs;var dynamicContentObj;var closeButtons;var refActiveTabContent;var callbackOnTabSwitch;this.initActiveTabIndex=0;this.callbackOnTabSwitch='';this.refActiveTabContent='';this.textPadding=3;this.strictDocType=true;this.ajaxObjects=new Array();this.tabTitles=new Array();this.layoutCSS='tab-view.css';this.maxNumberOfTabs=6;this.dynamicContentObj=false;this.closeButtons=new Array();this.width='100%';this.height='500';try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')}} -DHTMLSuite.tabView.prototype={init:function(){DHTMLSuite.commonObj.loadCSS(this.layoutCSS);this.outsideObjectRefIndex=refToTabViewObjects.length;refToTabViewObjects[this.outsideObjectRefIndex]=this;try{this.dynamicContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include DHTMLSuite-dynamicContent.js')} -this.__initializeAndParseTabs(false,false)},setCallbackOnTabSwitch:function(callbackOnTabSwitch){this.callbackOnTabSwitch=callbackOnTabSwitch},getMaximumNumberOfTabs:function(){return this.maxNumberOfTabs},setMaximumTabs:function(maximumNumberOfTabs){this.maxNumberOfTabs=maximumNumberOfTabs},setParentId:function(idOfParentHTMLElement){this.tabSetParentId=idOfParentHTMLElement;this.DHTMLSuite_tabObj=document.getElementById(idOfParentHTMLElement)},setWidth:function(newWidth){this.width=newWidth},setHeight:function(newHeight){this.height=newHeight},setIndexActiveTab:function(indexOfNewActiveTab){this.initActiveTabIndex=indexOfNewActiveTab},setTabTitles:function(titleOfTabs){this.tabTitles=titleOfTabs},setCloseButtons:function(closeButtons){this.closeButtons=closeButtons},getReferenceToDivElementByTitle:function(tabTitle){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){var obj=document.getElementById('tabView'+this.tabSetParentId+'_'+index);return obj} -return false},getReferenceToDivElementById:function(idOfTab){var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');for(var no=0;no=this.maxNumberOfTabs)return;var div=document.createElement('DIV');div.className='DHTMLSuite_aTab';this.DHTMLSuite_tabObj.appendChild(div);var tabId=this.__initializeAndParseTabs(true,tabTitle,closeButton);if(tabContent)div.innerHTML=tabContent;if(tabContentUrl){this.dynamicContentObj.loadContent('tabView'+parentId+'_'+tabId,tabContentUrl)} -this.tabTitles[tabId]=tabTitle;return true},deleteTab:function(tabLabel,tabIndex){if(tabLabel){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){this.deleteTab(false,index)}}else if(tabIndex>=0){if(document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex)){var obj=document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex);var id=obj.parentNode.parentNode.id;DHTMLSuite.discardElement(obj);var obj2=document.getElementById('tabView'+this.tabSetParentId+'_'+tabIndex);DHTMLSuite.discardElement(obj2);this.__resetTabIds(this.tabSetParentId);this.initActiveTabIndex=-1;var newIndex=0;if(refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex==tabIndex)refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex=-1;this.__showTab(this.tabSetParentId,newIndex,this.outsideObjectRefIndex)}}},addContentToTab:function(tabLabel,filePath){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){this.dynamicContentObj.loadContent('tabView'+this.tabSetParentId+'_'+index,filePath)}},displayATab:function(tabLabel,tabIndex){if(tabLabel){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){this.initActiveTabIndex=index}else return false}else{this.initActiveTabIndex=tabIndex} -this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex) -},getTabIndex:function(){var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');var tabIndex=0;for(var no=0;no=0){if(divs[no].className!='tabInactive')return tabIndex;tabIndex++}} -return tabIndex},__setPadding:function(obj,padding){var span=obj.getElementsByTagName('SPAN')[0];span.style.paddingLeft=padding+'px';span.style.paddingRight=padding+'px'},__showTab:function(parentId,tabIndex,objectIndex){var parentId_div=parentId+"_";if(!document.getElementById('tabView'+parentId_div+tabIndex)){return} -if(refToTabViewObjects[objectIndex].activeTabIndex>=0){if(refToTabViewObjects[objectIndex].activeTabIndex==tabIndex){return} -var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex);if(!obj){refToTabViewObjects[objectIndex].activeTabIndex=0;var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex)} -obj.className='tabInactive';obj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')';var imgs=obj.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif';document.getElementById('tabView'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex).style.display='none'} -var thisObj=document.getElementById('tabTab'+parentId_div+tabIndex);thisObj.className='tabActive';thisObj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_active.gif'+'\')';var imgs=thisObj.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_active.gif';document.getElementById('tabView'+parentId_div+tabIndex).style.display='block';this.refActiveTabContent=document.getElementById('tabView'+parentId_div+tabIndex);refToTabViewObjects[objectIndex].activeTabIndex=tabIndex;refToTabViewObjects[objectIndex].__handleCallback('tabSwitch');var parentObj=thisObj.parentNode;var aTab=parentObj.getElementsByTagName('DIV')[0];countObjects=0;var startPos=2;var previousObjectActive=false;while(aTab){if(aTab.tagName=='DIV'){if(previousObjectActive){previousObjectActive=false;startPos-=2} -if(aTab==thisObj){startPos-=2;previousObjectActive=true;refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding+1)}else{refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding)} -aTab.style.left=startPos+'px';countObjects++;startPos+=2} -aTab=aTab.nextSibling} -return},__handleCallback:function(action){var callbackString='';switch(action){case "tabSwitch":callbackString=this.callbackOnTabSwitch;break} -if(callbackString){callbackString=callbackString+'(this.refActiveTabContent)';eval(callbackString)}},__tabClick:function(inputObj,index){var idArray=inputObj.id.split('_');var parentId=inputObj.getAttribute('parentRefId');if(!parentId)parentId=inputObj.parentRefId;this.__showTab(parentId,idArray[idArray.length-1].replace(/[^0-9]/gi,''),index)},__rolloverTab:function(){if(this.className.indexOf('tabInactive')>=0){this.className='inactiveTabOver';this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_over.gif'+'\')';var imgs=this.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_over.gif'}},__rolloutTab:function(){if(this.className== 'inactiveTabOver'){this.className='tabInactive';this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')';var imgs=this.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif'}},__initializeAndParseTabs:function(additionalTab,nameOfAdditionalTab,additionalCloseButton){this.DHTMLSuite_tabObj.className=' DHTMLSuite_tabWidget';window.refToThisTabSet=this;if(!additionalTab||additionalTab=='undefined'){this.DHTMLSuite_tabObj=document.getElementById(this.tabSetParentId);this.width=this.width+'';if(this.width.indexOf('%')<0)this.width= this.width+'px';this.DHTMLSuite_tabObj.style.width=this.width;this.height=this.height+'';if(this.height.length>0){if(this.height.indexOf('%')<0)this.height= this.height+'px';this.DHTMLSuite_tabObj.style.height=this.height} -var tabDiv=document.createElement('DIV');var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0];this.DHTMLSuite_tabObj.insertBefore(tabDiv,firstDiv);tabDiv.className='DHTMLSuite_tabContainer';this.tabView_countTabs=0;var tmpTabTitles=this.tabTitles}else{var tabDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0];var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[1];this.initActiveTabIndex=this.tabView_countTabs;var tmpTabTitles=Array(nameOfAdditionalTab)} -for(var no=0;no0){if(this.height.indexOf('%')==-1){var tmpHeight=(this.height.replace('px','')/1-22);tabs[no].style.height=tmpHeight+'px'}else -tabs[no].style.height=this.height} -tabs[no].style.display='none';if(tabs[no].id){tabs[no].setAttribute('originalId',tabs[no].id);tabs[no].originalId=tabs[no].id} -tabs[no].id='tabView'+this.tabSetParentId+"_"+divCounter;divCounter++}} -if(additionalTab){this.tabView_countTabs++}else{this.tabView_countTabs=this.tabView_countTabs+this.tabTitles.length} -this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex);return this.activeTabIndex},__mouseOutEffectForCloseButton:function(){this.src=this.src.replace('close-over.gif','close.gif')},__mouseOverEffectCloseButton:function(){this.src=this.src.replace('close.gif','close-over.gif')},__fillTabWithContentFromAjax:function(ajaxIndex,objId,tabId){var obj=document.getElementById('tabView'+objId+'_'+tabId);obj.innerHTML=this.ajaxObjects[ajaxIndex].response},__resetTabIds:function(parentId){var tabTitleCounter=0;var tabContentCounter=0;var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');for(var no=0;no=0&&divs[no].parentNode.parentNode==this.DHTMLSuite_tabObj){divs[no].id='tabTab'+parentId+'_'+tabContentCounter;tabContentCounter++}} -this.tabView_countTabs=tabContentCounter},getTabIndexByTitle:function(tabTitle){tabTitle=tabTitle.replace(/(.*?) .*$/gi,'$1');var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');for(var no=0;no=0){var span=divs[no].getElementsByTagName('SPAN')[0];var spanTitle=span.innerHTML.replace(/(.*?) .*$/gi,'$1');if(spanTitle==tabTitle){var tmpId=divs[no].id.split('_');return tmpId[tmpId.length-1].replace(/[^0-9]/g,'')/1}}} -return-1},getTabTitle:function(){return(this.tabTitles[this.activeTabIndex])}} -var JSTreeObj;var treeUlCounter=0;var nodeId=1;DHTMLSuite.JSDragDropTree=function(){var idOfTree;var folderImage;var plusImage;var minusImage;var maximumDepth;var dragNode_source;var dragNode_parent;var dragNode_sourceNextSib;var dragNode_noSiblings;var dragNode_destination;var floatingContainer;var dragDropTimer;var dropTargetIndicator;var insertAsSub;var indicator_offsetX;var indicator_offsetX_sub;var indicator_offsetY;var messageMaximumDepthReached;var ajaxObjects;var layoutCSS;var cookieName;this.folderImage='DHTMLSuite_folder.gif';this.plusImage='DHTMLSuite_plus.gif';this.minusImage='DHTMLSuite_minus.gif';this.maximumDepth=6;this.layoutCSS='drag-drop-folder-tree.css';this.floatingContainer=document.createElement('UL');this.floatingContainer.style.position='absolute';this.floatingContainer.style.display='none';this.floatingContainer.id='floatingContainer';this.insertAsSub=false;document.body.appendChild(this.floatingContainer);this.dragDropTimer=-1;this.dragNode_noSiblings=false;this.cookieName='DHTMLSuite_expandedNodes';if(document.all){this.indicator_offsetX=1;this.indicator_offsetX_sub=1;this.indicator_offsetY=13}else{this.indicator_offsetX=1;this.indicator_offsetX_sub=3;this.indicator_offsetY=5} -if(navigator.userAgent.indexOf('Opera')>=0){this.indicator_offsetX=2;this.indicator_offsetX_sub=3;this.indicator_offsetY=-7} -this.messageMaximumDepthReached='';this.ajaxObjects=new Array();try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} -var objectIndex;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} -DHTMLSuite.JSDragDropTree.prototype={init:function(){var ind=this.objectIndex;DHTMLSuite.commonObj.loadCSS(this.layoutCSS);JSTreeObj=this;this.__createDropIndicator();if(!document.documentElement.onselectstart)document.documentElement.onselectstart=function(){return DHTMLSuite.commonObj.__isTextSelOk()};document.documentElement.ondragstart=document.documentElement.ondragstart=function(){return false};DHTMLSuite.commonObj.__addEventEl(document.documentElement);var nodeId=0;var DHTMLSuite_tree=document.getElementById(this.idOfTree);var menuItems=DHTMLSuite_tree.getElementsByTagName('LI');for(var no=0;no0&&subItems[0].style.display!='block'){this.showHideNode(false,menuItems[no].id)}}},collapseAll:function(){var menuItems=document.getElementById(this.idOfTree).getElementsByTagName('LI');for(var no=0;no0&&subItems[0].style.display=='block'){this.showHideNode(false,menuItems[no].id)}}},showHideNode:function(e,inputId){if(inputId){if(!document.getElementById(inputId))return;thisNode=document.getElementById(inputId).getElementsByTagName('IMG')[0]}else {if(document.all)e=event;var srcEl=DHTMLSuite.commonObj.getSrcElement(e);thisNode=srcEl;if(srcEl.tagName=='A')thisNode=srcEl.parentNode.getElementsByTagName('IMG')[0]} -if(thisNode.style.visibility=='hidden')return;var parentNode=thisNode.parentNode;inputId=parentNode.id.replace(/[^0-9]/g,'');if(thisNode.src.indexOf(this.plusImage)>=0){thisNode.src=thisNode.src.replace(this.plusImage,this.minusImage);var ul=parentNode.getElementsByTagName('UL')[0];ul.style.display='block';if(!initExpandedNodes)initExpandedNodes=',';if(initExpandedNodes.indexOf(','+inputId+',')<0)initExpandedNodes=initExpandedNodes+inputId+','}else{thisNode.src=thisNode.src.replace(this.minusImage,this.plusImage);parentNode.getElementsByTagName('UL')[0].style.display='none';initExpandedNodes=initExpandedNodes.replace(','+inputId,'')} -DHTMLSuite.commonObj.setCookie(this.cookieName,initExpandedNodes,500);return false},getSaveString:function(initObj,saveString){if(!saveString)var saveString='';if(!initObj){initObj=document.getElementById(this.idOfTree)} -var lis=initObj.getElementsByTagName('LI');if(lis.length>0){var li=lis[0];while(li){if(li.id){if(saveString.length>0)saveString=saveString+',';saveString=saveString+li.id.replace(/[^0-9]/gi,'');saveString=saveString+'-';if(li.parentNode.id!=this.idOfTree)saveString=saveString+li.parentNode.parentNode.id.replace(/[^0-9]/gi,'');else saveString=saveString+'0';var ul=li.getElementsByTagName('UL');if(ul.length>0){saveString=this.getSaveString(ul[0],saveString)}} -li=li.nextSibling}} -if(initObj.id==this.idOfTree){return saveString} -return saveString},__initializeDragProcess:function(e){if(document.all)e=event;var subs=JSTreeObj.floatingContainer.getElementsByTagName('LI');if(subs.length>0){if(JSTreeObj.dragNode_sourceNextSib){JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib)}else{JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source)}} -JSTreeObj.dragNode_source=this.parentNode;JSTreeObj.dragNode_parent=this.parentNode.parentNode;JSTreeObj.dragNode_sourceNextSib=false;if(JSTreeObj.dragNode_source.nextSibling)JSTreeObj.dragNode_sourceNextSib=JSTreeObj.dragNode_source.nextSibling;JSTreeObj.dragNode_destination=false;JSTreeObj.dragDropTimer=0;DHTMLSuite.commonObj.__setTextSelOk(false);JSTreeObj.__waitBeforeDragProcessStarts();return false},__waitBeforeDragProcessStarts:function(){if(this.dragDropTimer>=0&&this.dragDropTimer<10){this.dragDropTimer=this.dragDropTimer+1;setTimeout('JSTreeObj.__waitBeforeDragProcessStarts()',20);return} -if(this.dragDropTimer==10){JSTreeObj.floatingContainer.style.display='block';JSTreeObj.floatingContainer.appendChild(JSTreeObj.dragNode_source)}},__moveDragableNodes:function(e,tagType){if(JSTreeObj.dragDropTimer<10)return;if(document.all)e=event;dragDrop_x=e.clientX/1+5+document.body.scrollLeft;dragDrop_y=e.clientY/1+5+document.documentElement.scrollTop;JSTreeObj.floatingContainer.style.left=dragDrop_x+'px';JSTreeObj.floatingContainer.style.top=dragDrop_y+'px';var thisObj=DHTMLSuite.commonObj.getSrcElement(e);var thisObjOrig=DHTMLSuite.commonObj.getSrcElement(e);if(thisObj.tagName=='A'||thisObj.tagName=='IMG')thisObj=thisObj.parentNode;JSTreeObj.dragNode_noSiblings=false;var tmpVar=thisObj.getAttribute('noSiblings');if(!tmpVar)tmpVar=thisObj.noSiblings;if(tmpVar=='true')JSTreeObj.dragNode_noSiblings=true;if(thisObj&&tagType){JSTreeObj.dragNode_destination=thisObj;var img=thisObj.getElementsByTagName('IMG')[1];var tmpObj= JSTreeObj.dropTargetIndicator;tmpObj.style.display='block';var eventSourceObj=thisObjOrig;if(JSTreeObj.dragNode_noSiblings&&eventSourceObj.tagName=='IMG')eventSourceObj=eventSourceObj.nextSibling;var tmpImg=tmpObj.getElementsByTagName('IMG')[0];if(thisObjOrig.tagName=='A'||JSTreeObj.dragNode_noSiblings){tmpImg.src=tmpImg.src.replace('ind1','ind2');JSTreeObj.insertAsSub=true;tmpObj.style.left=(DHTMLSuite.commonObj.getLeftPos(eventSourceObj)+JSTreeObj.indicator_offsetX_sub)+'px'}else{tmpImg.src=tmpImg.src.replace('ind2','ind1');JSTreeObj.insertAsSub=false;tmpObj.style.left=(DHTMLSuite.commonObj.getLeftPos(eventSourceObj)+JSTreeObj.indicator_offsetX)+'px'} -tmpObj.style.top=(DHTMLSuite.commonObj.getTopPos(thisObj)+JSTreeObj.indicator_offsetY)+'px'} -return false},__dropDragableNodes:function(){if(JSTreeObj.dragDropTimer<10){JSTreeObj.dragDropTimer=-1;DHTMLSuite.commonObj.__setTextSelOk(true);return} -var showMessage=false;if(JSTreeObj.dragNode_destination){var countUp=JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_destination,'up');var countDown=JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_source,'down');var countLevels=countUp/1+countDown/1+(JSTreeObj.insertAsSub?1:0);if(countLevels>JSTreeObj.maximumDepth){JSTreeObj.dragNode_destination=false;showMessage=true}} -if(JSTreeObj.dragNode_destination){if(JSTreeObj.insertAsSub){var uls=JSTreeObj.dragNode_destination.getElementsByTagName('UL');if(uls.length>0){ul=uls[0];ul.style.display='block';var lis=ul.getElementsByTagName('LI');if(lis.length>0){ul.insertBefore(JSTreeObj.dragNode_source,lis[0])}else {ul.appendChild(JSTreeObj.dragNode_source)}}else{var ul=document.createElement('UL');ul.style.display='block';JSTreeObj.dragNode_destination.appendChild(ul);ul.appendChild(JSTreeObj.dragNode_source)} -var img=JSTreeObj.dragNode_destination.getElementsByTagName('IMG')[0];img.style.visibility='visible';img.src=img.src.replace(JSTreeObj.plusImage,JSTreeObj.minusImage)}else{if(JSTreeObj.dragNode_destination.nextSibling){var nextSib=JSTreeObj.dragNode_destination.nextSibling;nextSib.parentNode.insertBefore(JSTreeObj.dragNode_source,nextSib)}else{JSTreeObj.dragNode_destination.parentNode.appendChild(JSTreeObj.dragNode_source)}} -var tmpObj=JSTreeObj.dragNode_parent;var lis=tmpObj.getElementsByTagName('LI');if(lis.length==0){var img=tmpObj.parentNode.getElementsByTagName('IMG')[0];img.style.visibility='hidden';DHTMLSuite.discardElement(tmpObj)}}else{if(JSTreeObj.dragNode_sourceNextSib){JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib)}else{JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source)}} -JSTreeObj.dropTargetIndicator.style.display='none';JSTreeObj.dragDropTimer=-1;DHTMLSuite.commonObj.__setTextSelOk(true);if(showMessage&&JSTreeObj.messageMaximumDepthReached)alert(JSTreeObj.messageMaximumDepthReached)},__createDropIndicator:function(){this.dropTargetIndicator=document.createElement('DIV');this.dropTargetIndicator.style.zIndex=240000;this.dropTargetIndicator.style.position='absolute';this.dropTargetIndicator.style.display='none';var img=document.createElement('IMG');img.src=DHTMLSuite.configObj.imagePath+'drag-drop-tree/'+'dragDrop_ind1.gif';img.id='dragDropIndicatorImage';this.dropTargetIndicator.appendChild(img);document.body.appendChild(this.dropTargetIndicator)},__getDepthOfABranchInTheTree:function(obj,direction,stopAtObject){var countLevels=0;if(direction=='up'){while(obj.parentNode&&obj.parentNode!=stopAtObject){obj=obj.parentNode;if(obj.tagName=='UL')countLevels=countLevels/1+1} -return countLevels} -if(direction=='down'){var subObjects=obj.getElementsByTagName('LI');for(var no=0;no
'} -if(this.waitMessage){waitMessageToShow=waitMessageToShow+'
'+this.waitMessage+'
'} -if(this.waitMessage!=null&&this.waitImage!=null){try{if(waitMessageToShow.length>0)document.getElementById(divId).innerHTML=waitMessageToShow}catch(e){}} -waitMessageToShow=false;var ajaxIndex=this.ajaxObjects.length;try{this.ajaxObjects[ajaxIndex]=new sack()}catch(e){alert('Could not create ajax object. Please make sure that ajax.js is included')} -if(url.indexOf('?')>=0){this.ajaxObjects[ajaxIndex].method='GET';var string=url.substring(url.indexOf('?'));url=url.replace(string,'');string=string.replace('?','');var items=string.split(/&/g);for(var no=0;no'}} -DHTMLSuite.sliderObjects=new Array();DHTMLSuite.indexOfCurrentlyActiveSlider=false;DHTMLSuite.slider_generalMouseEventsAdded=false;DHTMLSuite.slider=function(){var width;var height;var targetObj;var sliderWidth;var sliderDirection;var functionToCallOnChange;var layoutCss;var sliderMaxValue;var sliderMinValue;var initialValue;var sliderSize;var directionOfPointer;var slideInProcessTimer;var indexThisSlider;var numberOfSteps;var stepLinesVisibility;var slide_event_pos;var slide_start_pos;var sliderHandleImg;var sliderName;var sliderValueReversed;this.sliderWidth=9;this.layoutCss='slider.css';this.sliderDirection='hor';this.width=0;this.height=0;this.sliderMaxValue=100;this.sliderMinValue=0;this.initialValue=0;this.targetObj=false;this.directionOfPointer='up';this.slideInProcessTimer=-1;this.sliderName='';this.numberOfSteps=false;this.stepLinesVisibility=true;this.sliderValueReversed=false;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} -var objectIndex;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} -DHTMLSuite.slider.prototype={init:function(){if(!this.targetObj){alert('Error!-No target for slider specified');return} -this.__setWidthAndHeightDynamically();DHTMLSuite.commonObj.loadCSS(this.layoutCss);this.__createSlider();if(!document.documentElement.onselectstart)document.documentElement.onselectstart=function(){return DHTMLSuite.commonObj.__isTextSelOk()}},setSliderTarget:function(targetRef){targetRef=DHTMLSuite.commonObj.getEl(targetRef);this.targetObj=targetRef},setSliderDirection:function(newDirection){newDirection=newDirection+'';newDirection=newDirection.toLowerCase();if(newDirection!='hor'&&newDirection!='ver'){alert('Invalid slider direction-possible values: "hor" or "ver"');return} -this.sliderDirection=newDirection},setSliderWidth:function(newWidth){newWidth=newWidth+'';if(newWidth.indexOf('%')==-1)newWidth=newWidth+'px';this.width=newWidth},setSliderHeight:function(newHeight){newHeight=newHeight+'';if(newHeight.indexOf('%')==-1)newHeight=newHeight+'px';this.height=height},setSliderReversed:function(){this.sliderValueReversed=true},setOnChangeEvent:function(nameOfFunction){this.functionToCallOnChange=nameOfFunction},setSliderMaxValue:function(newMaxValue){this.sliderMaxValue=newMaxValue},setSliderMinValue:function(newMinValue){this.sliderMinValue=newMinValue},setSliderName:function(nameOfSlider){this.sliderName=nameOfSlider},setLayoutCss:function(nameOfNewCssFile){this.layoutCss=nameOfNewCssFile},setInitialValue:function(newInitialValue){this.initialValue=newInitialValue},setSliderPointerDirection:function(directionOfPointer){this.directionOfPointer=directionOfPointer},setSliderValue:function(newValue){var position=Math.floor((newValue/this.sliderMaxValue)*this.sliderSize);if(this.sliderDirection=='hor'){this.sliderHandleImg.style.left=position+'px'}else{this.sliderHandleImg.style.top=position+'px'}},setNumberOfSliderSteps:function(numberOfSteps){this.numberOfSteps=numberOfSteps},setStepLinesVisible:function(visible){this.stepLinesVisibility=visible},__setWidthAndHeightDynamically:function(){if(!this.width||this.width==0)this.width=this.targetObj.clientWidth+'';if(!this.height||this.height==0)this.height=this.targetObj.clientHeight+'';if(!this.width||this.width==0)this.width=this.targetObj.offsetWidth+'';if(!this.height||this.height==0)this.height=this.targetObj.offsetHeight+'';if(this.width==0)return;if(this.height==0)return;if(this.width.indexOf('px')==-1&&this.width.indexOf('%')==-1)this.width=this.width+'px';if(this.height.indexOf('px')==-1&&this.height.indexOf('%')==-1)this.height=this.height+'px'},__createSlider:function(initWidth){if(this.targetObj.clientWidth==0||initWidth==0){var timeoutTime=100;setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+this.objectIndex+'].__createSlider('+this.targetObj.clientWidth+')',timeoutTime);return} -this.__setWidthAndHeightDynamically();this.indexThisSlider=DHTMLSuite.sliderObjects.length;DHTMLSuite.sliderObjects[this.indexThisSlider]=this;window.refToThisObject=this;var div=document.createElement('DIV');div.style.width=this.width;div.style.cursor='default';div.style.height=this.height;div.style.position='relative';div.id='sliderNumber'+this.indexThisSlider;div.onmousedown=this.__setPositionFromClick;DHTMLSuite.commonObj.__addEventEl(div);this.targetObj.appendChild(div);var sliderObj=document.createElement('DIV');if(this.sliderDirection=='hor'){sliderObj.className='DHTMLSuite_slider_horizontal';sliderObj.style.width=div.clientWidth+'px';this.sliderSize=div.offsetWidth-this.sliderWidth;var sliderHandle=document.createElement('IMG');var srcHandle='slider_handle_down.gif';sliderHandle.style.bottom='2px';if(this.directionOfPointer=='up'){srcHandle='slider_handle_up.gif';sliderHandle.style.bottom='0px'} -sliderHandle.src=DHTMLSuite.configObj.imagePath+'slider/'+srcHandle;div.appendChild(sliderHandle);var leftPos;if(this.sliderValueReversed){leftPos=Math.round(((this.sliderMaxValue-this.initialValue)/this.sliderMaxValue)*this.sliderSize)-1}else{leftPos=Math.round((this.initialValue/this.sliderMaxValue)*this.sliderSize)} -sliderHandle.style.left= leftPos+'px'}else{sliderObj.className='DHTMLSuite_slider_vertical';sliderObj.style.height=div.clientHeight+'px';this.sliderSize=div.clientHeight-this.sliderWidth;var sliderHandle=document.createElement('IMG');var srcHandle='slider_handle_right.gif';sliderHandle.style.left='0px';if(this.directionOfPointer=='left'){srcHandle='slider_handle_left.gif';sliderHandle.style.left='0px'} -sliderHandle.src=DHTMLSuite.configObj.imagePath+'slider/'+srcHandle;div.appendChild(sliderHandle);var topPos;if(!this.sliderValueReversed){topPos=Math.floor(((this.sliderMaxValue-this.initialValue)/this.sliderMaxValue)*this.sliderSize)}else{topPos=Math.floor((this.initialValue/this.sliderMaxValue)*this.sliderSize)} -sliderHandle.style.top=topPos+'px'} -sliderHandle.id='sliderForObject'+this.indexThisSlider;sliderHandle.style.position='absolute';sliderHandle.style.zIndex=5;sliderHandle.onmousedown=this.__initializeSliderDrag;sliderHandle.ondragstart=function(){return false};sliderHandle.onselectstart=function(){return false};DHTMLSuite.commonObj.__addEventEl(sliderHandle);this.sliderHandleImg=sliderHandle;if(!DHTMLSuite.slider_generalMouseEventsAdded){DHTMLSuite.commonObj.addEvent(document.documentElement,"mousemove",this.__moveSlider);DHTMLSuite.commonObj.addEvent(document.documentElement,"mouseup",this.__stopSlideProcess);DHTMLSuite.slider_generalMouseEventsAdded=true} -sliderObj.innerHTML='';div.appendChild(sliderObj);if(this.numberOfSteps&&this.stepLinesVisibility){var stepSize=this.sliderSize/this.numberOfSteps;for(var no=0;no<=this.numberOfSteps;no++){var lineDiv=document.createElement('DIV');lineDiv.style.position='absolute';lineDiv.innerHTML='';div.appendChild(lineDiv);if(this.sliderDirection=='hor'){lineDiv.className='DHTMLSuite_smallLines_vertical';lineDiv.style.left=Math.floor((stepSize*no)+(this.sliderWidth/2))+'px'}else{lineDiv.className='DHTMLSuite_smallLines_horizontal';lineDiv.style.top=Math.floor((stepSize*no)+(this.sliderWidth/2))+'px';lineDiv.style.left='14px'}}}},__initializeSliderDrag:function(e){if(document.all)e=event;DHTMLSuite.commonObj.__setTextSelOk(false);var numIndex=this.id.replace(/[^0-9]/gi,'');var sliderObj=DHTMLSuite.sliderObjects[numIndex];DHTMLSuite.indexOfCurrentlyActiveSlider=numIndex;sliderObj.slideInProcessTimer=0;if(sliderObj.sliderDirection=='hor'){sliderObj.slide_event_pos=e.clientX;sliderObj.slide_start_pos=this.style.left.replace('px','')/1}else{sliderObj.slide_event_pos=e.clientY;sliderObj.slide_start_pos=this.style.top.replace('px','')/1} -sliderObj.__waitBeforeSliderDragStarts();return false},__setPositionFromClick:function(e){if(document.all)e=event;if(e.target)srcEvent=e.target;else if(e.srcElement)srcEvent=e.srcElement;if(srcEvent.nodeType==3) -srcEvent=srcEvent.parentNode;if(srcEvent.tagName!='DIV')return;var numIndex=this.id.replace(/[^0-9]/gi,'');var sliderObj=DHTMLSuite.sliderObjects[numIndex];if(sliderObj.numberOfSteps){modValue=sliderObj.sliderSize/sliderObj.numberOfSteps} -if(sliderObj.sliderDirection=='hor'){var handlePos=(e.clientX-DHTMLSuite.commonObj.getLeftPos(this)- Math.ceil(sliderObj.sliderWidth/2))}else{var handlePos=(e.clientY-DHTMLSuite.commonObj.getTopPos(this)- Math.ceil(sliderObj.sliderWidth/2))} -if(sliderObj.numberOfSteps){var mod=handlePos % modValue;if(mod>(modValue/2))mod=modValue-mod;else mod*=-1;handlePos=handlePos+mod} -if(handlePos<0)handlePos=0;if(handlePos > sliderObj.sliderSize)handlePos=sliderObj.sliderSize;if(sliderObj.sliderDirection=='hor'){sliderObj.sliderHandleImg.style.left=handlePos+'px';if(!sliderObj.sliderValueReversed){returnValue=Math.round((handlePos/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}else{returnValue=Math.round(((sliderObj.sliderSize-handlePos)/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}}else{sliderObj.sliderHandleImg.style.top=handlePos+'px';if(sliderObj.sliderValueReversed){returnValue=Math.round((handlePos/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}else{returnValue=Math.round(((sliderObj.sliderSize-handlePos)/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}} -returnValue=returnValue+sliderObj.sliderMinValue;if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange+'('+returnValue+',"'+sliderObj.sliderName+'","click")');DHTMLSuite.indexOfCurrentlyActiveSlider=numIndex;sliderObj.slideInProcessTimer=10;if(sliderObj.sliderDirection=='hor'){sliderObj.slide_event_pos=e.clientX;sliderObj.slide_start_pos=handlePos}else{sliderObj.slide_event_pos=e.clientY;sliderObj.slide_start_pos=handlePos} -DHTMLSuite.commonObj.__setTextSelOk(false)},__waitBeforeSliderDragStarts:function(){if(this.slideInProcessTimer<10&&this.slideInProcessTimer>=0){this.slideInProcessTimer+=2;window.refToThisSlider=this;setTimeout('window.refToThisSlider.__waitBeforeSliderDragStarts()',5)}},__moveSlider:function(e){if(DHTMLSuite.indexOfCurrentlyActiveSlider===false)return;var sliderObj=DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider];if(document.all)e=event;if(sliderObj.slideInProcessTimer<10)return;var returnValue=sliderObj.__getSliderValue(e);if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange+'('+returnValue+',"'+sliderObj.sliderName+'","move")')},__getSliderValue:function(e){var returnValue;if(this.numberOfSteps){modValue=this.sliderSize/this.numberOfSteps} -if(this.sliderDirection=='hor'){var handlePos=e.clientX-this.slide_event_pos+this.slide_start_pos}else{var handlePos=e.clientY-this.slide_event_pos+this.slide_start_pos} -if(this.numberOfSteps){var mod=handlePos % modValue;if(mod>(modValue/2))mod=modValue-mod;else mod*=-1;handlePos=handlePos+mod} -if(handlePos<0)handlePos=0;if(handlePos > this.sliderSize)handlePos=this.sliderSize;if(this.sliderDirection=='hor'){this.sliderHandleImg.style.left=handlePos+'px';if(!this.sliderValueReversed){returnValue=Math.round((handlePos/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}else{returnValue=Math.round(((this.sliderSize-handlePos)/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}}else{this.sliderHandleImg.style.top=handlePos+'px';if(this.sliderValueReversed){returnValue=Math.round((handlePos/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}else{returnValue=Math.round(((this.sliderSize-handlePos)/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}} -returnValue=returnValue+this.sliderMinValue;return returnValue},__stopSlideProcess:function(e){if(document.all)e=event;DHTMLSuite.commonObj.__setTextSelOk(true);if(!DHTMLSuite.indexOfCurrentlyActiveSlider)return;var sliderObj=DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider];sliderObj.slideInProcessTimer=-1;var returnValue=sliderObj.__getSliderValue(e);if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange+'('+returnValue+',"'+sliderObj.sliderName+'","mouseup")')}} -DHTMLSuite.modalMessage=function(props){var url;var htmlOfModalMessage;var domRef;var divs_transparentDiv;var divs_content;var iframeEl;var layoutCss;var width;var height;var isModal;var existingBodyOverFlowStyle;var dynContentObj;var cssClassOfMessageBox;var shadowDivVisible;var shadowOffset;var objectIndex;this.url='';this.htmlOfModalMessage='';this.layoutCss='modal-message.css';this.height=200;this.width=400;this.cssClassOfMessageBox=false;this.shadowDivVisible=true;this.shadowOffset=5;this.isModal=true;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} -this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this;var ind=this.objectIndex;DHTMLSuite.commonObj.addEvent(window,"resize",function(){DHTMLSuite.variableStorage.arrayDSObjects[ind].__resizeTransparentDiv()});if(props)this.__setInitialProps(props)} -DHTMLSuite.modalMessage.prototype={__setInitialProps:function(props){if(props.url)this.setSource(props.url);if(props.htmlOfModalMessage)this.setHtmlContent(props.htmlOfModalMessage);if(props.domRef)this.setDomReference(props.domRef);if(props.width)this.width=props.width;if(props.height)this.height=props.height;if(props.cssClassOfMessageBox)this.cssClassOfMessageBox=props.cssClassOfMessageBox;if(props.shadowOffset)this.shadowOffset=props.shadowOffset;if(props.shadowDivVisible)this.shadowDivVisible=props.shadowDivVisible;if(props.isModal||props.isModal===false||props.isModal===0)this.isModal=props.isModal;if(props.waitMessage)this.setWaitMessage(waitMessage)},setIsModal:function(isModal){this.isModal=isModal},setSource:function(urlOfSource){if(urlOfSource)this.__clearProperties();this.url=urlOfSource},setHtmlContent:function(newHtmlContent){if(newHtmlContent)this.__clearProperties();this.htmlOfModalMessage=newHtmlContent},setDomReference:function(domRef){if(domRef)this.__clearProperties();if(domRef)domRef=DHTMLSuite.commonObj.getEl(domRef);if(domRef){domRef=domRef.cloneNode(true)} -this.domRef=domRef},setSize:function(width,height){if(width)this.width=width;if(height)this.height=height},setCssClassMessageBox:function(newCssClass){this.cssClassOfMessageBox=newCssClass;if(this.divs_content){if(this.cssClassOfMessageBox) -this.divs_content.className=this.cssClassOfMessageBox;else -this.divs_content.className='modalDialog_contentDiv'}},setShadowOffset:function(newShadowOffset){this.shadowOffset=newShadowOffset -},setWaitMessage:function(newMessage){if(!this.dynContentObj){try{this.dynContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include dhtmlSuite-dynamicContent.js')}} -this.dynContentObj.setWaitMessage(newMessage)},setWaitImage:function(newImage){if(!this.dynContentObj){try{this.dynContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include dhtmlSuite-dynamicContent.js')}} -this.dynContentObj.setWaitImage(newImage)},setCache:function(cacheStatus){if(!this.dynContentObj){try{this.dynContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include dhtmlSuite-dynamicContent.js')}} -this.dynContentObj.setCache(cacheStatus)},display:function(){var ind=this.objectIndex;if(!this.divs_transparentDiv){DHTMLSuite.commonObj.loadCSS(this.layoutCss);this.__createDivElements()} -this.__resizeAndPositionDivElements();if(this.isModal){this.divs_transparentDiv.style.display='block'}else{this.divs_transparentDiv.style.display='none'} -this.divs_content.style.display='block';this.divs_shadow.style.display='block';if(this.iframeEl){setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+ind+'].iframeEl.style.display="block"',150)} -this.__resizeAndPositionDivElements();window.refToThisModalBoxObj=this;setTimeout('window.refToThisModalBoxObj.__resizeAndPositionDivElements()',100);this.__addHTMLContent()},setShadowDivVisible:function(visible){this.shadowDivVisible=visible},close:function(){document.documentElement.style.overflow='';this.divs_transparentDiv.style.display='none';this.divs_content.style.display='none';this.divs_shadow.style.display='none';if(this.iframeEl)this.iframeEl.style.display='none'},__clearProperties:function(){if(this.domRef)DHTMLSuite.discardElement(this.domRef);this.domRef=null;this.url=false;this.htmlOfModalMessage=false},__createDivElements:function(){this.divs_transparentDiv=document.createElement('DIV');this.divs_transparentDiv.className='DHTMLSuite_modalDialog_transparentDivs';this.divs_transparentDiv.style.left='0px';this.divs_transparentDiv.style.top='0px';this.divs_transparentDiv.id='transparentDiv';document.body.appendChild(this.divs_transparentDiv);if(!document.getElementById('DHTMLSuite_modalBox_contentDiv')){this.divs_content=document.createElement('DIV');this.divs_content.className='DHTMLSuite_modalDialog_contentDiv';this.divs_content.id='DHTMLSuite_modalBox_contentDiv';document.body.appendChild(this.divs_content)}else{this.divs_content=document.getElementById('DHTMLSuite_modalBox_contentDiv')} -this.divs_shadow=document.createElement('DIV');this.divs_shadow.className='DHTMLSuite_modalDialog_contentDiv_shadow';document.body.appendChild(this.divs_shadow);if(DHTMLSuite.clientInfoObj.isMSIE){this.iframeEl=document.createElement('';this.formRef.method=this.method;this.formRef.action=this.action;this.formRef.target=this.iframeName;if(!this.formRef.enctype)this.formRef.enctype='multipart/form-data'},__getIframeResponse:function(){if(this.responseEl){if(this.responseFile){if(!this.responseEl.id)this.responseEl.id='DHTMLSuite_formResponse'+DHTMLSuite.getUniqueId();var dynContent=new DHTMLSuite.dynamicContent();dynContent.loadContent(this.responseEl.id,this.responseFile)}else{this.responseEl.innerHTML=self.frames[this.iframeName].document.body.innerHTML;DHTMLSuite.commonObj.__evaluateJs(this.responseEl);DHTMLSuite.commonObj.__evaluateCss(this.responseEl)}} -this.coverDiv.style.display='none';this.__handleCallback('onComplete')},__positionCoverDiv:function(){if(!this.responseEl)return;try{var st=this.coverDiv.style;st.left=DHTMLSuite.commonObj.getLeftPos(this.responseEl)+'px';st.top=DHTMLSuite.commonObj.getTopPos(this.responseEl)+'px';st.width=this.responseEl.offsetWidth+'px';st.height=this.responseEl.offsetHeight+'px';st.display='block'}catch(e){}},__createCoverDiv:function(){if(this.coverDiv)return;this.coverDiv=document.createElement('DIV');var el=this.coverDiv;el.style.overflow='hidden';el.style.zIndex=1000;el.style.position='absolute';document.body.appendChild(el);var innerDiv=document.createElement('DIV');innerDiv.style.width='105%';innerDiv.style.height='105%';innerDiv.className='DHTMLSuite_formCoverDiv';innerDiv.style.opacity='0.2';innerDiv.style.filter='alpha(opacity=20)';el.appendChild(innerDiv);var ajaxLoad=document.createElement('DIV');ajaxLoad.className='DHTMLSuite_formCoverDiv_ajaxLoader';el.appendChild(ajaxLoad)},__createSackObject:function(ajaxIndex){var ind=this.objectIndex;this.sackObj[ajaxIndex]=new sack();this.sackObj[ajaxIndex].requestFile=this.action;this.sackObj[ajaxIndex].method=this.method;this.sackObj[ajaxIndex].onCompletion=function(){DHTMLSuite.variableStorage.arrayDSObjects[ind].__getResponse(ajaxIndex)}},__getResponse:function(ajaxIndex){if(this.responseEl){if(this.responseFile){if(!this.responseEl.id)this.responseEl.id='DHTMLSuite_formResponse'+DHTMLSuite.getUniqueId();var dynContent=new DHTMLSuite.dynamicContent();dynContent.loadContent(this.responseEl.id,this.responseFile)}else{this.responseEl.innerHTML=this.sackObj[ajaxIndex].response;DHTMLSuite.commonObj.__evaluateJs(this.responseEl);DHTMLSuite.commonObj.__evaluateCss(this.responseEl)}} -this.coverDiv.style.display='none';this.sackObj[ajaxIndex]=null;this.__handleCallback('onComplete')},__populateSack:function(ajaxIndex){var els=this.formUtil.getValuesAsArray(this.formRef);for(var prop in els){if(DHTMLSuite.commonObj.isArray(els[prop])){for(var no=0;no=0){name=prop.replace('[','['+no)} -this.sackObj[ajaxIndex].setVar(name,els[prop][no])}}else{this.sackObj[ajaxIndex].setVar(prop,els[prop])}}},__setInitProperties:function(props){if(props.formRef)this.formRef=DHTMLSuite.commonObj.getEl(props.formRef);if(props.method)this.method=props.method;if(props.responseEl)this.responseEl=DHTMLSuite.commonObj.getEl(props.responseEl);if(props.action)this.action=props.action;if(props.responseFile)this.responseFile=props.responseFile;if(props.callbackOnComplete)this.callbackOnComplete=props.callbackOnComplete;if(!this.action)this.action=this.formRef.action;if(!this.method)this.method=this.formRef.method},__handleCallback:function(action){var callbackString='';switch(action){case "onComplete":callbackString=this.callbackOnComplete;break} -if(callbackString){if(callbackString.indexOf('(')==-1)callbackString=callbackString+'("'+this.formRef.name+'")';eval(callbackString)}}} -DHTMLSuite.autoComplete=function(){var layoutCss;var ajaxBox_offsetX;var ajaxBox_offsetY;var minimumLettersBeforeLookup;var ajax_list_currentLetters;var ajax_list_cachedLists -var ajax_optionDiv;var ajax_list_MSIE;var ajax_list_activeItem;var ajax_list_objects;var ajax_list_activeInput;var ajax_list_activeItem;var ajax_list_optionDivFirstItem -var ajax_optionDiv;var ajax_optionDiv_iframe;this.layoutCss='auto-complete.css';this.ajaxBox_offsetX=0;this.ajaxBox_offsetY=0;this.ajax_list_currentLetters=new Array();this.ajax_list_cachedLists=new Array();this.ajax_optionDiv=false;this.ajax_list_MSIE=false;if(navigator.userAgent.indexOf('MSIE')>=0&&navigator.userAgent.indexOf('Opera')<0) -this.ajax_list_MSIE=true;this.ajax_list_activeItem;this.ajax_list_objects=new Array();this.ajax_list_activeInput=false;this.ajax_list_activeItem;this.ajax_list_optionDivFirstItem=false;this.ajax_optionDiv=false;this.ajax_optionDiv_iframe=false;var ajax_list_MSIE=false;if(navigator.userAgent.indexOf('MSIE')>=0&&navigator.userAgent.indexOf('Opera')<0)ajax_list_MSIE=true;this.minimumLettersBeforeLookup=1;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} -this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this;document.body.setAttribute("objectIndex",this.objectIndex);DHTMLSuite.commonObj.loadCSS(this.layoutCss)} -DHTMLSuite.autoComplete.prototype={add:function(inputObjId,externalFile){var refObject=DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex];eval("document.getElementById('"+inputObjId+"').onkeyup=function(e){refObject.__showOptions(e,'"+inputObjId+"','"+externalFile+"')};");DHTMLSuite.commonObj.__addEventEl(document.getElementById(inputObjId))},setLayoutCss:function(newCssFileName){this.layoutCss=newCssFileName},__showOptions:function(e,inputObjId,externalFile){var inputObj=document.getElementById(inputObjId);var ind=this.objectIndex;if(document.all)e=event;if(e.keyCode==13||e.keyCode==9)return;if(this.ajax_list_currentLetters[inputObj.name]==inputObj.value)return;if(!this.ajax_list_cachedLists[inputObj.id])this.ajax_list_cachedLists[inputObj.id]=new Array();this.ajax_list_currentLetters[inputObj.name]=inputObj.value;if(!this.ajax_optionDiv){this.ajax_optionDiv=document.createElement('DIV');this.ajax_optionDiv.id='ajax_listOfOptions';document.body.appendChild(this.ajax_optionDiv);if(this.ajax_list_MSIE){this.ajax_optionDiv_iframe=document.createElement('IFRAME');this.ajax_optionDiv_iframe.border='0';this.ajax_optionDiv_iframe.style.width=this.ajax_optionDiv.clientWidth+'px';this.ajax_optionDiv_iframe.style.height=this.ajax_optionDiv.clientHeight+'px';this.ajax_optionDiv_iframe.id='ajax_listOfOptions_iframe';document.body.appendChild(this.ajax_optionDiv_iframe)} -var allInputs=document.getElementsByTagName('INPUT');for(var no=0;no this.ajax_optionDiv.offsetHeight){this.ajax_optionDiv.scrollTop=this.ajax_list_activeItem.offsetTop-this.ajax_optionDiv.offsetHeight+this.ajax_list_activeItem.offsetHeight+2 } -if(this.ajax_list_activeItem.offsetTop < this.ajax_optionDiv.scrollTop){this.ajax_optionDiv.scrollTop=0}}},__ajaxOptionResize:function(inputObj){this.ajax_optionDiv.style.top =(this.__ajaxGetTopPos(inputObj)+inputObj.offsetHeight+this.ajaxBox_offsetY)+'px';this.ajax_optionDiv.style.left=(this.__ajaxGetLeftPos(inputObj)+this.ajaxBox_offsetX)+'px';if(this.ajax_optionDiv_iframe){this.ajax_optionDiv_iframe.style.left=this.ajax_optionDiv.style.left;this.ajax_optionDiv_iframe.style.top=this.ajax_optionDiv.style.top}},__ajaxGetTopPos:function(inputObj){var returnValue=inputObj.offsetTop;while((inputObj=inputObj.offsetParent)!=null){returnValue+= inputObj.offsetTop} -return returnValue},__ajaxGetLeftPos:function(inputObj){var returnValue=inputObj.offsetLeft;while((inputObj=inputObj.offsetParent)!=null)returnValue+= inputObj.offsetLeft;return returnValue},__ajaxOptionListShowContent:function(ajaxIndex,inputObj){var letters=inputObj.value;var content=this.ajax_list_objects[ajaxIndex].response;var elements=content.split('|');this.ajax_list_cachedLists[inputObj.id][letters.toLowerCase()]=elements;this.__ajaxOptionListBuildList(letters,inputObj.id)},__ajaxOptionListBuildList:function(letters,inputObjId){var ind=this.objectIndex;this.ajax_optionDiv.innerHTML='';this.ajax_list_activeItem=false;if(this.ajax_list_cachedLists[inputObjId][letters.toLowerCase()].length<=1){this.__ajaxOptionsHide();return} -this.ajax_list_optionDivFirstItem=false;var optionsAdded=false;for(var no=0;no');document.write('');depCache[files[no]]=true}}} +DHTMLSuite.discardElement=function(element){element=DHTMLSuite.commonObj.getEl(element);var gBin=document.getElementById('IELeakGBin');if(!gBin){gBin=document.createElement('DIV');gBin.id='IELeakGBin';gBin.style.display='none';document.body.appendChild(gBin)} +gBin.appendChild(element);gBin.innerHTML=''} +DHTMLSuite.createStandardObjects=function(){DHTMLSuite.clientInfoObj=new DHTMLSuite.clientInfo();DHTMLSuite.clientInfoObj.init();if(!DHTMLSuite.configObj){DHTMLSuite.configObj=new DHTMLSuite.config();DHTMLSuite.configObj.init()} +DHTMLSuite.commonObj=new DHTMLSuite.common();DHTMLSuite.variableStorage=new DHTMLSuite.globalVariableStorage();;DHTMLSuite.commonObj.init();DHTMLSuite.domQueryObj=new DHTMLSuite.domQuery();DHTMLSuite.commonObj.addEvent(window,'unload',function(){DHTMLSuite.commonObj.__clearMemoryGarbage()});standardObjectsCreated=true} +DHTMLSuite.config=function(){var imagePath;var cssPath;var defaultCssPath;var defaultImagePath} +DHTMLSuite.config.prototype={init:function(){this.imagePath=DHTML_SUITE_THEME_FOLDER+DHTML_SUITE_THEME+'/images/';this.cssPath=DHTML_SUITE_THEME_FOLDER+DHTML_SUITE_THEME+'/css/';this.defaultCssPath=this.cssPath;this.defaultImagePath=this.imagePath},setCssPath:function(newCssPath){this.cssPath=newCssPath},resetCssPath:function(){this.cssPath=this.defaultCssPath},resetImagePath:function(){this.imagePath=this.defaultImagePath},setImagePath:function(newImagePath){this.imagePath=newImagePath}} +DHTMLSuite.globalVariableStorage=function(){var menuBar_highlightedItems;this.menuBar_highlightedItems=new Array();var arrayDSObjects;var arrayOfDhtmlSuiteObjects;this.arrayDSObjects=new Array();this.arrayOfDhtmlSuiteObjects=this.arrayDSObjects;var ajaxObjects;this.ajaxObjects=new Array()} +DHTMLSuite.globalVariableStorage.prototype={} +DHTMLSuite.common=function(){var loadedCSSFiles;var cssCacheStatus;var eventEls;var isOkToSelect;this.okToSelect=true;this.cssCacheStatus=true;this.eventEls=new Array()} +DHTMLSuite.common.prototype={init:function(){this.loadedCSSFiles=new Array()},loadCSS:function(cssFile,prefixConfigPath){if(!prefixConfigPath&&prefixConfigPath!==false)prefixConfigPath=true;if(!this.loadedCSSFiles[cssFile]){this.loadedCSSFiles[cssFile]=true;var lt=document.createElement('LINK');if(!this.cssCacheStatus){if(cssFile.indexOf('?')>=0)cssFile=cssFile+'&';else cssFile=cssFile+'?';cssFile=cssFile+'rand='+Math.random()} +if(prefixConfigPath){lt.href=DHTMLSuite.configObj.cssPath+cssFile}else{lt.href=cssFile} +lt.rel='stylesheet';lt.media='screen';lt.type='text/css';document.getElementsByTagName('HEAD')[0].appendChild(lt)}},__setTextSelOk:function(okToSelect){this.okToSelect=okToSelect},__isTextSelOk:function(){return this.okToSelect},setCssCacheStatus:function(cssCacheStatus){this.cssCacheStatus=cssCacheStatus},getEl:function(elRef){if(typeof elRef=='string'){if(document.getElementById(elRef))return document.getElementById(elRef);if(document.forms[elRef])return document.forms[elRef];if(document[elRef])return document[elRef];if(window[elRef])return window[elRef]} +return elRef},isArray:function(el){if(el.constructor.toString().indexOf("Array")!=-1)return true;return false},getStyle:function(el,property){el=this.getEl(el);if(document.defaultView&&document.defaultView.getComputedStyle){var retVal=null;var comp=document.defaultView.getComputedStyle(el,'');if(comp){retVal=comp[property]} +return el.style[property]||retVal} +if(document.documentElement.currentStyle&&DHTMLSuite.clientInfoObj.isMSIE){var retVal=null;if(el.currentStyle)value=el.currentStyle[property];return(el.style[property]||retVal)} +return el.style[property]},getLeftPos:function(el){if(document.getBoxObjectFor){if(el.tagName!='INPUT'&&el.tagName!='SELECT'&&el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).x +} +var returnValue=el.offsetLeft;while((el=el.offsetParent)!=null){if(el.tagName!='HTML'){returnValue+= el.offsetLeft;if(document.all)returnValue+=el.clientLeft}} +return returnValue},getTopPos:function(el){if(document.getBoxObjectFor){if(el.tagName!='INPUT'&&el.tagName!='SELECT'&&el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).y +} +var returnValue=el.offsetTop;while((el=el.offsetParent)!=null){if(el.tagName!='HTML'){returnValue+=(el.offsetTop-el.scrollTop);if(document.all)returnValue+=el.clientTop}} +return returnValue},getCookie:function(name){var start=document.cookie.indexOf(name+"=");var len=start+name.length+1;if((!start)&&(name!=document.cookie.substring(0,name.length)))return null;if(start==-1)return null;var end=document.cookie.indexOf(";",len);if(end==-1)end=document.cookie.length;return unescape(document.cookie.substring(len,end))},setCookie:function(name,value,expires,path,domain,secure){expires=expires*60*60*24*1000;var today=new Date();var expires_date=new Date(today.getTime()+(expires));var cookieString=name+"="+escape(value)+ +((expires)?";expires="+expires_date.toGMTString():"")+ +((path)?";path="+path:"")+ +((domain)?";domain="+domain:"")+ +((secure)?";secure":"");document.cookie=cookieString},deleteCookie:function(name,path,domain){if(this.getCookie(name))document.cookie=name+"="+ +((path)?";path="+path:"")+ +((domain)?";domain="+domain:"")+ +";expires=Thu,01-Jan-1970 00:00:01 GMT"},cancelEvent:function(){return false},addEvent:function(obj,type,fn,suffix){if(!suffix)suffix='';if(obj.attachEvent){if(typeof DHTMLSuite_funcs[type+fn+suffix]!='function'){DHTMLSuite_funcs[type+fn+suffix]=function(){fn.apply(window.event.srcElement)};obj.attachEvent('on'+type,DHTMLSuite_funcs[type+fn+suffix])} +obj=null} else {obj.addEventListener(type,fn,false)} +this.__addEventEl(obj)},removeEvent:function(obj,type,fn,suffix){if(obj.detachEvent){obj.detachEvent('on'+type,DHTMLSuite_funcs[type+fn+suffix]);DHTMLSuite_funcs[type+fn+suffix]=null;obj=null} else {obj.removeEventListener(type,fn,false)}},__clearMemoryGarbage:function(){if(!DHTMLSuite.clientInfoObj.isMSIE)return;for(var no=0;no';img.outerHTML=html},__evaluateJs:function(obj){obj=this.getEl(obj);var scriptTags=obj.getElementsByTagName('SCRIPT');var string='';var jsCode='';for(var no=0;no=0)?true:false;this.isFirefox=(this.browser.toLowerCase().indexOf('firefox')>=0)?true:false;this.isMSIE=(this.browser.toLowerCase().indexOf('msie')>=0)?true:false;this.isOldMSIE=(this.browser.toLowerCase().match(/msie\s[0-6]/gi))?true:false;this.isSafari=(this.browser.toLowerCase().indexOf('safari')>=0)?true:false;this.navigatorVersion=navigator.appVersion.replace(/.*?MSIE\s(\d\.\d).*/g,'$1')/1;this.isOldMSIE=(this.isMSIE&&this.navigatorVersion<7)?true:false},getBrowserWidth:function(){if(self.innerWidth)return self.innerWidth;return document.documentElement.offsetWidth},getBrowserHeight:function(){if(self.innerHeight)return self.innerHeight;return document.documentElement.offsetHeight}} +DHTMLSuite.domQuery=function(){document.getElementsByClassName=this.getElementsByClassName;document.getElementsByAttribute=this.getElementsByAttribute} +DHTMLSuite.domQuery.prototype={} +DHTMLSuite.tableWidgetPageHandler=function(){var tableRef;var targetRef;var txtPrevious;var txtNext;var txtFirst;var txtLast;var txtResultPrefix;var txtResultTo;var txtResultOf;var totalNumberOfRows;var rowsPerPage;var layoutCSS;var activePageNumber;var mainDivEl;var resultDivElement;var pageListDivEl;var objectIndex;var linkPagePrefix;var linkPageSuffix;var maximumNumberOfPageLinks;var callbackOnAfterNavigate;this.txtPrevious='Previous';this.txtNext='Next';this.txtResultPrefix='Result: ';this.txtResultTo='to';this.txtResultOf='of';this.txtFirst='First';this.txtLast='Last';this.tableRef=false;this.targetRef=false;this.totalNumberOfRows=false;this.activePageNumber=0;this.layoutCSS='table-widget-page-handler.css';this.linkPagePrefix='';this.linkPageSuffix='';this.maximumNumberOfPageLinks=false;this.callbackOnAfterNavigate=false;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} +DHTMLSuite.tableWidgetPageHandler.prototype={setTableRef:function(tableRef){this.tableRef=tableRef;this.tableRef.setPageHandler(this)},setTargetId:function(idOfHTMLElement){if(!document.getElementById(idOfHTMLElement)){alert('ERROR IN tableWidgetPageHandler.setTargetId:\nElement with id '+idOfHTMLElement+' does not exists');return} +this.targetRef=document.getElementById(idOfHTMLElement)},setTxtPrevious:function(newText){this.txtPrevious=newText},setLinkPagePrefix:function(linkPagePrefix){this.linkPagePrefix=linkPagePrefix},setLinkPageSuffix:function(linkPageSuffix){this.linkPageSuffix=linkPageSuffix},setTxtNext:function(newText){this.txtNext=newText},setTxtResultOf:function(txtResultOf){this.txtResultOf=txtResultOf},setTxtResultTo:function(txtResultTo){this.txtResultTo=txtResultTo},setTxtResultPrefix:function(txtResultPrefix){this.txtResultPrefix=txtResultPrefix},setTxtFirstPage:function(txtFirst){this.txtFirst=txtFirst},setTxtLastPage:function(txtLast){this.txtLast=txtLast},setTotalNumberOfRows:function(totalNumberOfRows){this.totalNumberOfRows=totalNumberOfRows},setCallbackOnAfterNavigate:function(callbackOnAfterNavigate){this.callbackOnAfterNavigate=callbackOnAfterNavigate},setLayoutCss:function(layoutCSS){this.layoutCSS=layoutCSS},setMaximumNumberOfPageLinks:function(maximumNumberOfPageLinks){this.maximumNumberOfPageLinks=maximumNumberOfPageLinks},init:function(){this.rowsPerPage=this.tableRef.getServersideSortNumberOfRows();DHTMLSuite.commonObj.loadCSS(this.layoutCSS);this.__createMainDivEls();this.setHTMLOfResultList();this.__createPageLinks();this.goToPage(1)},__createMainDivEls:function(){if(!this.targetRef){alert('Error creating table widget page handler. Remember to specify targetRef');return} +this.mainDivEl=document.createElement('DIV');this.mainDivEl.className='DHTMLSuite_tableWidgetPageHandler_mainDiv';this.targetRef.appendChild(this.mainDivEl);this.resultDivElement=document.createElement('DIV');this.resultDivElement.className='DHTMLSuite_tableWidgetPageHandler_result';this.mainDivEl.appendChild(this.resultDivElement);this.pageListDivEl=document.createElement('DIV');this.pageListDivEl.className='DHTMLSuite_tableWidgetPageHandler_pageList';this.mainDivEl.appendChild(this.pageListDivEl)},setHTMLOfResultList:function(){this.resultDivElement.innerHTML='';var html=this.txtResultPrefix+(((this.activePageNumber-1)*this.rowsPerPage)+1)+' '+this.txtResultTo+' '+Math.min(this.totalNumberOfRows,(this.activePageNumber*this.rowsPerPage))+' '+this.txtResultOf+' '+this.totalNumberOfRows;this.resultDivElement.innerHTML=html},__createPageLinks:function(){var ind=this.objectIndex;this.pageListDivEl.innerHTML='';var numberOfPages=Math.ceil(this.totalNumberOfRows/this.rowsPerPage);if(this.maximumNumberOfPageLinks&&this.maximumNumberOfPageLinks=0){var pageNo=src.id.replace(/[^0-9]/gi,'')/1;this.activePageNumber=pageNo} +if(src.id=='next'){this.activePageNumber++;if(this.activePageNumber>numberOfPages)this.activePageNumber=numberOfPages} +if(src.id=='previous'){this.activePageNumber--;if(this.activePageNumber<1)this.activePageNumber=1} +if(this.activePageNumber!=initActivePageNumber){this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage);this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate);this.setHTMLOfResultList();this.__createPageLinks()} +return false},__resetActivePageNumber:function(){this.activePageNumber=1;this.setHTMLOfResultList();this.__createPageLinks()},goToPage:function(pageNo){var initActivePageNumber=this.activePageNumber;this.activePageNumber=pageNo;if(this.activePageNumber!=initActivePageNumber){this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage);this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate);this.setHTMLOfResultList();this.__createPageLinks()}}} +DHTMLSuite.tableWidget=function(){var tableWidget_okToSort;var activeColumn;var idOfTable;var tableObj;var widthOfTable;var heightOfTable;var columnSortArray;var layoutCSS;var noCssLayout;var serversideSort;var serversideSortAscending;var tableCurrentlySortedBy;var serversideSortFileName;var serversideSortNumberOfRows;var serversideSortCurrentStartIndex;var serversideSortExtraSearchCriterias;var pageHandler;var rowClickCallBackFunction;var objectIndex;this.serversideSort=false;this.serversideSortAscending=true;this.tableCurrentlySortedBy=false;this.serversideSortFileName=false;this.serversideSortCurrentStartIndex=0;this.serversideSortExtraSearchCriterias='';this.rowClickCallBackFunction=false;this.setRowDblClickCallBackFunction=false;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} +this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} +DHTMLSuite.tableWidget.prototype={init:function(){this.tableWidget_okToSort=true;this.activeColumn=false;if(!this.layoutCSS)this.layoutCSS='table-widget.css';DHTMLSuite.commonObj.loadCSS(this.layoutCSS);this.__initTableWidget()},setLayoutCss:function(newCssFile){this.layoutCSS=newCssFile},setRowClickCallBack:function(rowClickCallBackFunction){this.rowClickCallBackFunction=rowClickCallBackFunction},setRowDblClickCallBack:function(setRowDblClickCallBackFunction){this.setRowDblClickCallBackFunction=setRowDblClickCallBackFunction},setServerSideSort:function(serversideSort){this.serversideSort=serversideSort},setServersideSearchCriterias:function(serversideSortExtraSearchCriterias){this.serversideSortExtraSearchCriterias=serversideSortExtraSearchCriterias},getServersideSortNumberOfRows:function(serversideSort){return this.serversideSortNumberOfRows},setServersideSortNumberOfRows:function(serversideSortNumberOfRows){this.serversideSortNumberOfRows=serversideSortNumberOfRows},setServersideSortFileName:function(serversideSortFileName){this.serversideSortFileName=serversideSortFileName},setNoCssLayout:function(){this.noCssLayout=true},sortTableByColumn:function(columnIndex,howToSort){if(!howToSort)howToSort='ascending';var tableObj=document.getElementById(this.idOfTable);var firstRow=tableObj.rows[0];var tds=firstRow.cells;if(tds[columnIndex]&&this.columnSortArray[columnIndex]){this.__sortTable(tds[columnIndex],howToSort)}},setTableId:function(idOfTable){this.idOfTable=idOfTable;try{this.tableObj=document.getElementById(idOfTable)}catch(e){}},setTableWidth:function(width){this.widthOfTable=width},setTableHeight:function(height){this.heightOfTable=height},setColumnSort:function(columnSortArray){this.columnSortArray=columnSortArray},addNewRow:function(cellContent){var tObj=document.getElementById(this.idOfTable);var tb=tObj.getElementsByTagName('TBODY')[0];var row=tb.insertRow(-1);for(var no=0;no=0){obj.style.width='100%';obj.parentNode.style.width=this.widthOfTable}else{obj.style.width=this.widthOfTable+'px';obj.parentNode.style.width=this.widthOfTable+'px'} +if(this.heightOfTable.indexOf('%')>=0){obj.parentNode.style.height=this.heightOfTable}else{obj.parentNode.style.height=this.heightOfTable+'px'}} +if(!DHTMLSuite.clientInfoObj.isMSIE){this.__addEndCol(obj)}else{obj.style.cssText='width:expression(this.parentNode.clientWidth)'} +obj.cellSpacing=0;obj.cellPadding=0;if(!this.noCssLayout)obj.className='DHTMLSuite_tableWidget';var tHead=obj.getElementsByTagName('THEAD')[0];var cells=tHead.getElementsByTagName('TD');var tBody=obj.getElementsByTagName('TBODY')[0];tBody.className='DHTMLSuite_scrollingContent';for(var no=0;no=0){obj.parentNode.style.overflow='auto'}}} +this.__parseDataRows(obj);var ind=this.objectIndex},__addEndCol:function(obj){var rows=obj.getElementsByTagName('TR');for(var no=0;no';cell.style.width='13px';cell.width='13';cell.style.overflow='hidden'}},__highlightTableHeader:function(){this.className='DHTMLSuite_tableWigdet_headerCellOver';if(document.all){var divObj=this.parentNode.parentNode.parentNode.parentNode;this.parentNode.style.top=divObj.scrollTop+'px'}},__removeHighlightEffectFromTableHeader:function(){this.className='DHTMLSuite_tableWidget_headerCell'},__mousedownOnTableHeader:function(){this.className='DHTMLSuite_tableWigdet_headerCellDown';if(document.all){var divObj=this.parentNode.parentNode.parentNode.parentNode;this.parentNode.style.top=divObj.scrollTop+'px'}},__sortNumeric:function(a,b){a=a.replace(/,/,'.');b=b.replace(/,/,'.');a=a.replace(/[^\d\.\/]/g,'');b=b.replace(/[^\d\.\/]/g,'');if(a.indexOf('/')>=0)a=eval(a);if(b.indexOf('/')>=0)b=eval(b);return a/1-b/1},__sortString:function(a,b){if(a.toUpperCase()< b.toUpperCase())return-1;if(a.toUpperCase()> b.toUpperCase())return 1;return 0},__parseDataContentFromServer:function(ajaxIndex){var content=DHTMLSuite.variableStorage.ajaxObjects[ajaxIndex].response;if(content.indexOf('|||')==-1&&content.indexOf('###')==-1){alert('Error in data from server\n'+content);return} +this.__clearDataRows();var rows=content.split('|||');for(var no=0;no1)this.__fillDataRow(items)} +this.__parseDataRows(this.tableObj)},__clearDataRows:function(){if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable);while(this.tableObj.rows.length>1){DHTMLSuite.discardElement(this.tableObj.rows[this.tableObj.rows.length-1])}},__fillDataRow:function(data){if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable);var tbody=this.tableObj.getElementsByTagName('TBODY')[0];var row=tbody.insertRow(-1);for(var no=0;no 0) +sembol='&';var url=this.serversideSortFileName+sembol+'sortBy='+this.tableCurrentlySortedBy+'&numberOfRows='+this.serversideSortNumberOfRows+'&sortAscending='+this.serversideSortAscending+'&startIndex='+this.serversideSortCurrentStartIndex+this.serversideSortExtraSearchCriterias;var index=DHTMLSuite.variableStorage.ajaxObjects.length;try{DHTMLSuite.variableStorage.ajaxObjects[index]=new sack()}catch(e){alert('Unable to create ajax object. Please make sure that the sack js file is included on your page(js/ajax.js)');return} +DHTMLSuite.variableStorage.ajaxObjects[index].requestFile=url;DHTMLSuite.variableStorage.ajaxObjects[index].onCompletion=function(){DHTMLSuite.variableStorage.arrayDSObjects[objIndex].__parseDataContentFromServer(index);eval(callbackFunction)};DHTMLSuite.variableStorage.ajaxObjects[index].runAJAX()},__sortTable:function(obj,howToSort){if(this.serversideSort){if(!this.serversideSortFileName){alert('No server side file defined. Use the setServersideSortFileName to specify where to send the ajax request');return} +var sortBy=obj.getAttribute('sortBy');if(!sortBy)sortBy=obj.sortBy;if(!sortBy){alert('Sort is not defined. Remember to set a sortBy attribute on the header tags');return} +if(sortBy==this.tableCurrentlySortedBy)this.serversideSortAscending=!this.serversideSortAscending;else this.serversideSortAscending=true;if(howToSort)this.serversideSortAscending=(howToSort=='ascending'?true:false);this.tableCurrentlySortedBy=sortBy;this.serversideSortCurrentStartIndex =0;this.__getItemsFromServer();if(this.pageHandler)this.pageHandler.__resetActivePageNumber();this.__updateSortArrow(obj,this.serversideSortAscending?'ascending':'descending');return} +if(!this.tableWidget_okToSort)return;this.tableWidget_okToSort=false;var indexThis=0;var tmpObj=obj;while(tmpObj.previousSibling){tmpObj=tmpObj.previousSibling;if(tmpObj.tagName=='TD')indexThis++} +if(obj.getAttribute('direction')||obj.direction){direction=obj.getAttribute('direction');if(navigator.userAgent.indexOf('Opera')>=0)direction=obj.direction;if(direction=='ascending'||howToSort=='descending'){direction='descending';obj.setAttribute('direction','descending');obj.direction='descending'}else{direction='ascending';obj.setAttribute('direction','ascending');obj.direction='ascending'}}else{var curDir='ascending';if(howToSort)curDir=howToSort;direction=curDir;obj.setAttribute('direction',curDir);obj.direction=curDir} +this.__updateSortArrow(obj,direction);var tableObj=obj.parentNode.parentNode.parentNode;var tBody=tableObj.getElementsByTagName('TBODY')[0];var widgetIndex=tableObj.id.replace(/[^\d]/g,'');var sortMethod=this.columnSortArray[indexThis];var cellArray=new Array();var cellObjArray=new Array();for(var no=1;no=0;no--){for(var no2=0;no2DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=this.divElement.style.zIndex/1;DHTMLSuite_dragDropSimple_curZIndex=DHTMLSuite_dragDropSimple_curZIndex/1+1;this.divElement.style.zIndex=DHTMLSuite_dragDropSimple_curZIndex;if(this.cloneNode){var copy=this.divElement.cloneNode(true);this.divElement.parentNode.insertBefore(copy,this.divElement);copy.style.visibility='hidden';document.body.appendChild(this.divElement)} +DHTMLSuite.commonObj.addEvent(this.divElement,'mousedown',function(e){DHTMLSuite.variableStorage.arrayDSObjects[ind].__initDragProcess(e)},ind);DHTMLSuite.commonObj.addEvent(document.documentElement,'mousemove',function(e){DHTMLSuite.variableStorage.arrayDSObjects[ind].__moveDragableElement(e)},ind);DHTMLSuite.commonObj.addEvent(document.documentElement,'mouseup',function(e){DHTMLSuite.variableStorage.arrayDSObjects[ind].__stopDragProcess(e)},ind);if(!document.documentElement.onselectstart)document.documentElement.onselectstart=function(){return DHTMLSuite.commonObj.__isTextSelOk()}},setCallbackOnAfterDrag:function(functionName){this.callbackOnAfterDrag=functionName},setCallbackOnBeforeDrag:function(functionName){this.callbackOnBeforeDrag=functionName},addDragHandle:function(dragHandle){this.dragHandle[this.dragHandle.length]=dragHandle},__initDragProcess:function(e){if(document.all)e=event;var ind=this.objectIndex;DHTMLSuite_dragDropSimple_curObjIndex=ind;var thisObject=DHTMLSuite.variableStorage.arrayDSObjects[ind];if(!DHTMLSuite.commonObj.isObjectClicked(thisObject.divElement,e))return;if(thisObject.divElement.style.zIndex&&thisObject.divElement.style.zIndex/1>DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=thisObject.divElement.style.zIndex/1;DHTMLSuite_dragDropSimple_curZIndex=DHTMLSuite_dragDropSimple_curZIndex/1+1;thisObject.divElement.style.zIndex=DHTMLSuite_dragDropSimple_curZIndex;if(thisObject.callbackOnBeforeDrag){thisObject.__handleCallback('beforeDrag',e)} +if(thisObject.dragHandle.length>0){var objectFound;for(var no=0;no=0&&this.dragTimer<5){this.dragTimer++;setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+ind+'].__waitBeforeDragProcessStarts()',5)}},__moveDragableElement:function(e){if(document.all)e=event;var ind=this.objectIndex;var thisObj=DHTMLSuite.variableStorage.arrayDSObjects[ind];if(DHTMLSuite.clientInfoObj.isMSIE&&e.button!=1)return thisObj.__stopDragProcess();if(thisObj.dragTimer==5){if(thisObj.allowMoveX){var leftPos=(e.clientX-this.mouse_x+this.el_x);if(this.maxX!==false){if(leftPos+document.documentElement.scrollLeft>this.initialXPos+this.maxX){leftPos=this.initialXPos+this.maxX}} +if(this.minX!==false){if(leftPos+document.documentElement.scrollLeftthis.initialYPos+this.maxY){topPos=this.initialYPos+this.maxY}} +if(this.minY!==false){if(topPos DHTMLSuite_dragDropSimple_curZIndex){DHTMLSuite_dragDropSimple_curZIndex=zIndex/1+1}}} +DHTMLSuite.dragDrop=function(){var mouse_x;var mouse_y;var el_x;var el_y;var dragDropTimer;var numericIdToBeDragged;var dragObjCloneArray;var dragDropSourcesArray;var dragDropTargetArray;var currentZIndex;var okToStartDrag;var moveBackBySliding;var dragX_allowed;var dragY_allowed;var currentEl_allowX;var currentEl_allowY;var drag_minX;var drag_maxX;var drag_minY;var drag_maxY;var dragInProgress;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} +this.dragX_allowed=true;this.dragY_allowed=true;this.currentZIndex=21000;this.dragDropTimer=-1;this.dragObjCloneArray=new Array();this.numericIdToBeDragged=false;this.okToStartDrag=true;this.moveBackBySliding=true;this.dragInProgress=false;var objectIndex;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} +DHTMLSuite.dragDrop.prototype={init:function(){this.__initDragDropScript()},addSource:function(sourceId,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId){if(!this.dragDropSourcesArray)this.dragDropSourcesArray=new Array();if(!document.getElementById(sourceId)){alert('The source element with id '+sourceId+' does not exists. Check your HTML code');return} +if(xAxis!==false)xAxis=true;if(yAxis!==false)yAxis=true;var obj=document.getElementById(sourceId);this.dragDropSourcesArray[this.dragDropSourcesArray.length] =[obj,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId];obj.setAttribute('dragableElement',this.dragDropSourcesArray.length-1);obj.dragableElement=this.dragDropSourcesArray.length-1},addTarget:function(targetId,functionToCallOnDrop){if(!this.dragDropTargetArray)this.dragDropTargetArray=new Array();if(!document.getElementById(targetId))alert('The target element with id '+targetId+' does not exists. Check your HTML code');var obj=document.getElementById(targetId);this.dragDropTargetArray[this.dragDropTargetArray.length] =[obj,functionToCallOnDrop]},setSlide:function(isSlidingAnimationEnabled){this.moveBackBySliding=isSlidingAnimationEnabled},__initDragDropScript:function(){var ind=this.objectIndex;var refToThis=this;var startIndex=Math.random()+'';startIndex=startIndex.replace('.','')/1;for(var no=0;no=0&&this.dragDropTimer<5){this.dragDropTimer=this.dragDropTimer+1;setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+ind+'].__waitBeforeDragProcessStarts()',2);return} +if(this.dragDropTimer>=5){if(this.dragObjCloneArray[this.numericIdToBeDragged].style.display=='none'){this.dragDropSourcesArray[this.numericIdToBeDragged][0].style.visibility='hidden';var ref=this.dragObjCloneArray[this.numericIdToBeDragged];ref.style.display='block';ref.style.visibility='visible';ref.style.top=DHTMLSuite.commonObj.getTopPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0])+'px';ref.style.left=DHTMLSuite.commonObj.getLeftPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0])+'px'}}},__moveDragableElement:function(e){var ind=this.objectIndex;if(document.all)e=event;if(this.dragDropTimer<5)return false;if(this.dragInProgress)return false;this.dragInProgress=true;var dragObj=this.dragObjCloneArray[this.numericIdToBeDragged];if(this.currentEl_allowX){var leftPos=(e.clientX-this.mouse_x+this.el_x);if(this.drag_maxX){var tmpMaxX=this.drag_maxX-dragObj.offsetWidth;if(leftPos > tmpMaxX)leftPos=tmpMaxX +if(leftPos < this.drag_minX)leftPos=this.drag_minX} +dragObj.style.left=leftPos+'px'} +if(this.currentEl_allowY){var topPos=(e.clientY-this.mouse_y+this.el_y);if(this.drag_maxY){var tmpMaxY=this.drag_maxY-dragObj.offsetHeight;if(topPos > tmpMaxY)topPos=tmpMaxY;if(topPos < this.drag_minY)topPos=this.drag_minY} +dragObj.style.top=topPos+'px'} +this.dragInProgress=false;return false},__stopDragProcess:function(e){if(this.dragDropTimer<5)return false;if(document.all)e=event;var dropDestination=DHTMLSuite.commonObj.getSrcElement(e);var leftPosMouse=e.clientX+Math.max(document.body.scrollLeft,document.documentElement.scrollLeft);var topPosMouse=e.clientY+Math.max(document.body.scrollTop,document.documentElement.scrollTop);if(!this.dragDropTargetArray)this.dragDropTargetArray=new Array();for(var no=0;no leftPosEl&&leftPosMouse <(leftPosEl+widthEl)&&topPosMouse > topPosEl&&topPosMouse <(topPosEl+heightEl)){if(this.dragDropTargetArray[no][1]){try{eval(this.dragDropTargetArray[no][1]+'("'+this.dragDropSourcesArray[this.numericIdToBeDragged][0].id+'","'+this.dragDropTargetArray[no][0].id+'",'+e.clientX+','+e.clientY+')')}catch(e){alert('Unable to execute \n'+this.dragDropTargetArray[no][1]+'("'+this.dragDropSourcesArray[this.numericIdToBeDragged][0].id+'","'+this.dragDropTargetArray[no][0].id+'",'+e.clientX+','+e.clientY+')')}} +break}} +if(this.dragDropSourcesArray[this.numericIdToBeDragged][1]){this.__slideElementBackIntoItsOriginalPosition(this.numericIdToBeDragged)} +this.dragDropTimer=-1;DHTMLSuite.commonObj.__setTextSelOk(true);this.numericIdToBeDragged=false},__slideElementBackIntoItsOriginalPosition:function(numId){var currentX=this.dragObjCloneArray[numId].style.left.replace('px','')/1;var currentY=this.dragObjCloneArray[numId].style.top.replace('px','')/1;var ref=this.dragDropSourcesArray[numId][0];var targetX=DHTMLSuite.commonObj.getLeftPos(ref);var targetY=DHTMLSuite.commonObj.getTopPos(ref);;if(this.moveBackBySliding){this.__processSlideByPixels(numId,currentX,currentY,targetX,targetY)}else{this.dragObjCloneArray[numId].style.display='none';ref.style.visibility='visible'}},__processSlideByPixels:function(numId,currentX,currentY,targetX,targetY){var slideX=Math.round(Math.abs(Math.max(currentX,targetX)- Math.min(currentX,targetX))/10);var slideY=Math.round(Math.abs(Math.max(currentY,targetY)- Math.min(currentY,targetY))/10);if(slideY<3&&Math.abs(slideX)<10)slideY=3;if(slideX<3&&Math.abs(slideY)<10)slideX=3;if(currentX > targetX)slideX*=-1;if(currentY > targetY)slideY*=-1;currentX=currentX+slideX;currentY=currentY+slideY;if(Math.max(currentX,targetX)- Math.min(currentX,targetX)< 4)currentX=targetX;if(Math.max(currentY,targetY)- Math.min(currentY,targetY)< 4)currentY=targetY;this.dragObjCloneArray[numId].style.left=currentX+'px';this.dragObjCloneArray[numId].style.top=currentY+'px';if(currentX!=targetX||currentY!=targetY){window.thisRef=this;setTimeout('window.thisRef.__processSlideByPixels("'+numId+'",'+currentX+','+currentY+','+targetX+','+targetY+')',5)}else{this.dragObjCloneArray[numId].style.display='none';this.dragDropSourcesArray[numId][0].style.visibility='visible'}}} +if(!window.DHTMLSuite)var DHTMLSuite=new Object();/************************************************************************************************************ +*Tab view class +* +*Created:August,21st,2006 +* +*Update log:* +************************************************************************************************************/ +var refToTabViewObjects=new Array();DHTMLSuite.tabView=function(){var textPadding;var strictDocType ;var DHTMLSuite_tabObj;var activeTabIndex;var initActiveTabIndex;var ajaxObjects;var tabView_countTabs;var tabViewHeight;var tabSetParentId;var tabTitles;var width;var height;var layoutCSS;var outsideObjectRefIndex;var maxNumberOfTabs;var dynamicContentObj;var closeButtons;var refActiveTabContent;var callbackOnTabSwitch;this.initActiveTabIndex=0;this.callbackOnTabSwitch='';this.refActiveTabContent='';this.textPadding=3;this.strictDocType=true;this.ajaxObjects=new Array();this.tabTitles=new Array();this.layoutCSS='tab-view.css';this.maxNumberOfTabs=6;this.dynamicContentObj=false;this.closeButtons=new Array();this.width='100%';this.height='500';try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')}} +DHTMLSuite.tabView.prototype={init:function(){DHTMLSuite.commonObj.loadCSS(this.layoutCSS);this.outsideObjectRefIndex=refToTabViewObjects.length;refToTabViewObjects[this.outsideObjectRefIndex]=this;try{this.dynamicContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include DHTMLSuite-dynamicContent.js')} +this.__initializeAndParseTabs(false,false)},setCallbackOnTabSwitch:function(callbackOnTabSwitch){this.callbackOnTabSwitch=callbackOnTabSwitch},getMaximumNumberOfTabs:function(){return this.maxNumberOfTabs},setMaximumTabs:function(maximumNumberOfTabs){this.maxNumberOfTabs=maximumNumberOfTabs},setParentId:function(idOfParentHTMLElement){this.tabSetParentId=idOfParentHTMLElement;this.DHTMLSuite_tabObj=document.getElementById(idOfParentHTMLElement)},setWidth:function(newWidth){this.width=newWidth},setHeight:function(newHeight){this.height=newHeight},setIndexActiveTab:function(indexOfNewActiveTab){this.initActiveTabIndex=indexOfNewActiveTab},setTabTitles:function(titleOfTabs){this.tabTitles=titleOfTabs},setCloseButtons:function(closeButtons){this.closeButtons=closeButtons},getReferenceToDivElementByTitle:function(tabTitle){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){var obj=document.getElementById('tabView'+this.tabSetParentId+'_'+index);return obj} +return false},getReferenceToDivElementById:function(idOfTab){var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');for(var no=0;no=this.maxNumberOfTabs)return;var div=document.createElement('DIV');div.className='DHTMLSuite_aTab';this.DHTMLSuite_tabObj.appendChild(div);var tabId=this.__initializeAndParseTabs(true,tabTitle,closeButton);if(tabContent)div.innerHTML=tabContent;if(tabContentUrl){this.dynamicContentObj.loadContent('tabView'+parentId+'_'+tabId,tabContentUrl)} +this.tabTitles[tabId]=tabTitle;return true},deleteTab:function(tabLabel,tabIndex){if(tabLabel){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){this.deleteTab(false,index)}}else if(tabIndex>=0){if(document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex)){var obj=document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex);var id=obj.parentNode.parentNode.id;DHTMLSuite.discardElement(obj);var obj2=document.getElementById('tabView'+this.tabSetParentId+'_'+tabIndex);DHTMLSuite.discardElement(obj2);this.__resetTabIds(this.tabSetParentId);this.initActiveTabIndex=-1;var newIndex=0;if(refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex==tabIndex)refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex=-1;this.__showTab(this.tabSetParentId,newIndex,this.outsideObjectRefIndex)}}},addContentToTab:function(tabLabel,filePath){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){this.dynamicContentObj.loadContent('tabView'+this.tabSetParentId+'_'+index,filePath)}},displayATab:function(tabLabel,tabIndex){if(tabLabel){var index=this.getTabIndexByTitle(tabLabel);if(index!=-1){this.initActiveTabIndex=index}else return false}else{this.initActiveTabIndex=tabIndex} +this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex) +},getTabIndex:function(){var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');var tabIndex=0;for(var no=0;no=0){if(divs[no].className!='tabInactive')return tabIndex;tabIndex++}} +return tabIndex},__setPadding:function(obj,padding){var span=obj.getElementsByTagName('SPAN')[0];span.style.paddingLeft=padding+'px';span.style.paddingRight=padding+'px'},__showTab:function(parentId,tabIndex,objectIndex){var parentId_div=parentId+"_";if(!document.getElementById('tabView'+parentId_div+tabIndex)){return} +if(refToTabViewObjects[objectIndex].activeTabIndex>=0){if(refToTabViewObjects[objectIndex].activeTabIndex==tabIndex){return} +var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex);if(!obj){refToTabViewObjects[objectIndex].activeTabIndex=0;var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex)} +obj.className='tabInactive';obj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')';var imgs=obj.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif';document.getElementById('tabView'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex).style.display='none'} +var thisObj=document.getElementById('tabTab'+parentId_div+tabIndex);thisObj.className='tabActive';thisObj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_active.gif'+'\')';var imgs=thisObj.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_active.gif';document.getElementById('tabView'+parentId_div+tabIndex).style.display='block';this.refActiveTabContent=document.getElementById('tabView'+parentId_div+tabIndex);refToTabViewObjects[objectIndex].activeTabIndex=tabIndex;refToTabViewObjects[objectIndex].__handleCallback('tabSwitch');var parentObj=thisObj.parentNode;var aTab=parentObj.getElementsByTagName('DIV')[0];countObjects=0;var startPos=2;var previousObjectActive=false;while(aTab){if(aTab.tagName=='DIV'){if(previousObjectActive){previousObjectActive=false;startPos-=2} +if(aTab==thisObj){startPos-=2;previousObjectActive=true;refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding+1)}else{refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding)} +aTab.style.left=startPos+'px';countObjects++;startPos+=2} +aTab=aTab.nextSibling} +return},__handleCallback:function(action){var callbackString='';switch(action){case "tabSwitch":callbackString=this.callbackOnTabSwitch;break} +if(callbackString){callbackString=callbackString+'(this.refActiveTabContent)';eval(callbackString)}},__tabClick:function(inputObj,index){var idArray=inputObj.id.split('_');var parentId=inputObj.getAttribute('parentRefId');if(!parentId)parentId=inputObj.parentRefId;this.__showTab(parentId,idArray[idArray.length-1].replace(/[^0-9]/gi,''),index)},__rolloverTab:function(){if(this.className.indexOf('tabInactive')>=0){this.className='inactiveTabOver';this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_over.gif'+'\')';var imgs=this.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_over.gif'}},__rolloutTab:function(){if(this.className== 'inactiveTabOver'){this.className='tabInactive';this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')';var imgs=this.getElementsByTagName('IMG');var img=imgs[imgs.length-1];img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif'}},__initializeAndParseTabs:function(additionalTab,nameOfAdditionalTab,additionalCloseButton){this.DHTMLSuite_tabObj.className=' DHTMLSuite_tabWidget';window.refToThisTabSet=this;if(!additionalTab||additionalTab=='undefined'){this.DHTMLSuite_tabObj=document.getElementById(this.tabSetParentId);this.width=this.width+'';if(this.width.indexOf('%')<0)this.width= this.width+'px';this.DHTMLSuite_tabObj.style.width=this.width;this.height=this.height+'';if(this.height.length>0){if(this.height.indexOf('%')<0)this.height= this.height+'px';this.DHTMLSuite_tabObj.style.height=this.height} +var tabDiv=document.createElement('DIV');var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0];this.DHTMLSuite_tabObj.insertBefore(tabDiv,firstDiv);tabDiv.className='DHTMLSuite_tabContainer';this.tabView_countTabs=0;var tmpTabTitles=this.tabTitles}else{var tabDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0];var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[1];this.initActiveTabIndex=this.tabView_countTabs;var tmpTabTitles=Array(nameOfAdditionalTab)} +for(var no=0;no0){if(this.height.indexOf('%')==-1){var tmpHeight=(this.height.replace('px','')/1-22);tabs[no].style.height=tmpHeight+'px'}else +tabs[no].style.height=this.height} +tabs[no].style.display='none';if(tabs[no].id){tabs[no].setAttribute('originalId',tabs[no].id);tabs[no].originalId=tabs[no].id} +tabs[no].id='tabView'+this.tabSetParentId+"_"+divCounter;divCounter++}} +if(additionalTab){this.tabView_countTabs++}else{this.tabView_countTabs=this.tabView_countTabs+this.tabTitles.length} +this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex);return this.activeTabIndex},__mouseOutEffectForCloseButton:function(){this.src=this.src.replace('close-over.gif','close.gif')},__mouseOverEffectCloseButton:function(){this.src=this.src.replace('close.gif','close-over.gif')},__fillTabWithContentFromAjax:function(ajaxIndex,objId,tabId){var obj=document.getElementById('tabView'+objId+'_'+tabId);obj.innerHTML=this.ajaxObjects[ajaxIndex].response},__resetTabIds:function(parentId){var tabTitleCounter=0;var tabContentCounter=0;var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');for(var no=0;no=0&&divs[no].parentNode.parentNode==this.DHTMLSuite_tabObj){divs[no].id='tabTab'+parentId+'_'+tabContentCounter;tabContentCounter++}} +this.tabView_countTabs=tabContentCounter},getTabIndexByTitle:function(tabTitle){tabTitle=tabTitle.replace(/(.*?) .*$/gi,'$1');var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV');for(var no=0;no=0){var span=divs[no].getElementsByTagName('SPAN')[0];var spanTitle=span.innerHTML.replace(/(.*?) .*$/gi,'$1');if(spanTitle==tabTitle){var tmpId=divs[no].id.split('_');return tmpId[tmpId.length-1].replace(/[^0-9]/g,'')/1}}} +return-1},getTabTitle:function(){return(this.tabTitles[this.activeTabIndex])}} +var JSTreeObj;var treeUlCounter=0;var nodeId=1;DHTMLSuite.JSDragDropTree=function(){var idOfTree;var folderImage;var plusImage;var minusImage;var maximumDepth;var dragNode_source;var dragNode_parent;var dragNode_sourceNextSib;var dragNode_noSiblings;var dragNode_destination;var floatingContainer;var dragDropTimer;var dropTargetIndicator;var insertAsSub;var indicator_offsetX;var indicator_offsetX_sub;var indicator_offsetY;var messageMaximumDepthReached;var ajaxObjects;var layoutCSS;var cookieName;this.folderImage='DHTMLSuite_folder.gif';this.plusImage='DHTMLSuite_plus.gif';this.minusImage='DHTMLSuite_minus.gif';this.maximumDepth=6;this.layoutCSS='drag-drop-folder-tree.css';this.floatingContainer=document.createElement('UL');this.floatingContainer.style.position='absolute';this.floatingContainer.style.display='none';this.floatingContainer.id='floatingContainer';this.insertAsSub=false;document.body.appendChild(this.floatingContainer);this.dragDropTimer=-1;this.dragNode_noSiblings=false;this.cookieName='DHTMLSuite_expandedNodes';if(document.all){this.indicator_offsetX=1;this.indicator_offsetX_sub=1;this.indicator_offsetY=13}else{this.indicator_offsetX=1;this.indicator_offsetX_sub=3;this.indicator_offsetY=5} +if(navigator.userAgent.indexOf('Opera')>=0){this.indicator_offsetX=2;this.indicator_offsetX_sub=3;this.indicator_offsetY=-7} +this.messageMaximumDepthReached='';this.ajaxObjects=new Array();try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} +var objectIndex;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} +DHTMLSuite.JSDragDropTree.prototype={init:function(){var ind=this.objectIndex;DHTMLSuite.commonObj.loadCSS(this.layoutCSS);JSTreeObj=this;this.__createDropIndicator();if(!document.documentElement.onselectstart)document.documentElement.onselectstart=function(){return DHTMLSuite.commonObj.__isTextSelOk()};document.documentElement.ondragstart=document.documentElement.ondragstart=function(){return false};DHTMLSuite.commonObj.__addEventEl(document.documentElement);var nodeId=0;var DHTMLSuite_tree=document.getElementById(this.idOfTree);var menuItems=DHTMLSuite_tree.getElementsByTagName('LI');for(var no=0;no0&&subItems[0].style.display!='block'){this.showHideNode(false,menuItems[no].id)}}},collapseAll:function(){var menuItems=document.getElementById(this.idOfTree).getElementsByTagName('LI');for(var no=0;no0&&subItems[0].style.display=='block'){this.showHideNode(false,menuItems[no].id)}}},showHideNode:function(e,inputId){if(inputId){if(!document.getElementById(inputId))return;thisNode=document.getElementById(inputId).getElementsByTagName('IMG')[0]}else {if(document.all)e=event;var srcEl=DHTMLSuite.commonObj.getSrcElement(e);thisNode=srcEl;if(srcEl.tagName=='A')thisNode=srcEl.parentNode.getElementsByTagName('IMG')[0]} +if(thisNode.style.visibility=='hidden')return;var parentNode=thisNode.parentNode;inputId=parentNode.id.replace(/[^0-9]/g,'');if(thisNode.src.indexOf(this.plusImage)>=0){thisNode.src=thisNode.src.replace(this.plusImage,this.minusImage);var ul=parentNode.getElementsByTagName('UL')[0];ul.style.display='block';if(!initExpandedNodes)initExpandedNodes=',';if(initExpandedNodes.indexOf(','+inputId+',')<0)initExpandedNodes=initExpandedNodes+inputId+','}else{thisNode.src=thisNode.src.replace(this.minusImage,this.plusImage);parentNode.getElementsByTagName('UL')[0].style.display='none';initExpandedNodes=initExpandedNodes.replace(','+inputId,'')} +DHTMLSuite.commonObj.setCookie(this.cookieName,initExpandedNodes,500);return false},getSaveString:function(initObj,saveString){if(!saveString)var saveString='';if(!initObj){initObj=document.getElementById(this.idOfTree)} +var lis=initObj.getElementsByTagName('LI');if(lis.length>0){var li=lis[0];while(li){if(li.id){if(saveString.length>0)saveString=saveString+',';saveString=saveString+li.id.replace(/[^0-9]/gi,'');saveString=saveString+'-';if(li.parentNode.id!=this.idOfTree)saveString=saveString+li.parentNode.parentNode.id.replace(/[^0-9]/gi,'');else saveString=saveString+'0';var ul=li.getElementsByTagName('UL');if(ul.length>0){saveString=this.getSaveString(ul[0],saveString)}} +li=li.nextSibling}} +if(initObj.id==this.idOfTree){return saveString} +return saveString},__initializeDragProcess:function(e){if(document.all)e=event;var subs=JSTreeObj.floatingContainer.getElementsByTagName('LI');if(subs.length>0){if(JSTreeObj.dragNode_sourceNextSib){JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib)}else{JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source)}} +JSTreeObj.dragNode_source=this.parentNode;JSTreeObj.dragNode_parent=this.parentNode.parentNode;JSTreeObj.dragNode_sourceNextSib=false;if(JSTreeObj.dragNode_source.nextSibling)JSTreeObj.dragNode_sourceNextSib=JSTreeObj.dragNode_source.nextSibling;JSTreeObj.dragNode_destination=false;JSTreeObj.dragDropTimer=0;DHTMLSuite.commonObj.__setTextSelOk(false);JSTreeObj.__waitBeforeDragProcessStarts();return false},__waitBeforeDragProcessStarts:function(){if(this.dragDropTimer>=0&&this.dragDropTimer<10){this.dragDropTimer=this.dragDropTimer+1;setTimeout('JSTreeObj.__waitBeforeDragProcessStarts()',20);return} +if(this.dragDropTimer==10){JSTreeObj.floatingContainer.style.display='block';JSTreeObj.floatingContainer.appendChild(JSTreeObj.dragNode_source)}},__moveDragableNodes:function(e,tagType){if(JSTreeObj.dragDropTimer<10)return;if(document.all)e=event;dragDrop_x=e.clientX/1+5+document.body.scrollLeft;dragDrop_y=e.clientY/1+5+document.documentElement.scrollTop;JSTreeObj.floatingContainer.style.left=dragDrop_x+'px';JSTreeObj.floatingContainer.style.top=dragDrop_y+'px';var thisObj=DHTMLSuite.commonObj.getSrcElement(e);var thisObjOrig=DHTMLSuite.commonObj.getSrcElement(e);if(thisObj.tagName=='A'||thisObj.tagName=='IMG')thisObj=thisObj.parentNode;JSTreeObj.dragNode_noSiblings=false;var tmpVar=thisObj.getAttribute('noSiblings');if(!tmpVar)tmpVar=thisObj.noSiblings;if(tmpVar=='true')JSTreeObj.dragNode_noSiblings=true;if(thisObj&&tagType){JSTreeObj.dragNode_destination=thisObj;var img=thisObj.getElementsByTagName('IMG')[1];var tmpObj= JSTreeObj.dropTargetIndicator;tmpObj.style.display='block';var eventSourceObj=thisObjOrig;if(JSTreeObj.dragNode_noSiblings&&eventSourceObj.tagName=='IMG')eventSourceObj=eventSourceObj.nextSibling;var tmpImg=tmpObj.getElementsByTagName('IMG')[0];if(thisObjOrig.tagName=='A'||JSTreeObj.dragNode_noSiblings){tmpImg.src=tmpImg.src.replace('ind1','ind2');JSTreeObj.insertAsSub=true;tmpObj.style.left=(DHTMLSuite.commonObj.getLeftPos(eventSourceObj)+JSTreeObj.indicator_offsetX_sub)+'px'}else{tmpImg.src=tmpImg.src.replace('ind2','ind1');JSTreeObj.insertAsSub=false;tmpObj.style.left=(DHTMLSuite.commonObj.getLeftPos(eventSourceObj)+JSTreeObj.indicator_offsetX)+'px'} +tmpObj.style.top=(DHTMLSuite.commonObj.getTopPos(thisObj)+JSTreeObj.indicator_offsetY)+'px'} +return false},__dropDragableNodes:function(){if(JSTreeObj.dragDropTimer<10){JSTreeObj.dragDropTimer=-1;DHTMLSuite.commonObj.__setTextSelOk(true);return} +var showMessage=false;if(JSTreeObj.dragNode_destination){var countUp=JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_destination,'up');var countDown=JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_source,'down');var countLevels=countUp/1+countDown/1+(JSTreeObj.insertAsSub?1:0);if(countLevels>JSTreeObj.maximumDepth){JSTreeObj.dragNode_destination=false;showMessage=true}} +if(JSTreeObj.dragNode_destination){if(JSTreeObj.insertAsSub){var uls=JSTreeObj.dragNode_destination.getElementsByTagName('UL');if(uls.length>0){ul=uls[0];ul.style.display='block';var lis=ul.getElementsByTagName('LI');if(lis.length>0){ul.insertBefore(JSTreeObj.dragNode_source,lis[0])}else {ul.appendChild(JSTreeObj.dragNode_source)}}else{var ul=document.createElement('UL');ul.style.display='block';JSTreeObj.dragNode_destination.appendChild(ul);ul.appendChild(JSTreeObj.dragNode_source)} +var img=JSTreeObj.dragNode_destination.getElementsByTagName('IMG')[0];img.style.visibility='visible';img.src=img.src.replace(JSTreeObj.plusImage,JSTreeObj.minusImage)}else{if(JSTreeObj.dragNode_destination.nextSibling){var nextSib=JSTreeObj.dragNode_destination.nextSibling;nextSib.parentNode.insertBefore(JSTreeObj.dragNode_source,nextSib)}else{JSTreeObj.dragNode_destination.parentNode.appendChild(JSTreeObj.dragNode_source)}} +var tmpObj=JSTreeObj.dragNode_parent;var lis=tmpObj.getElementsByTagName('LI');if(lis.length==0){var img=tmpObj.parentNode.getElementsByTagName('IMG')[0];img.style.visibility='hidden';DHTMLSuite.discardElement(tmpObj)}}else{if(JSTreeObj.dragNode_sourceNextSib){JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib)}else{JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source)}} +JSTreeObj.dropTargetIndicator.style.display='none';JSTreeObj.dragDropTimer=-1;DHTMLSuite.commonObj.__setTextSelOk(true);if(showMessage&&JSTreeObj.messageMaximumDepthReached)alert(JSTreeObj.messageMaximumDepthReached)},__createDropIndicator:function(){this.dropTargetIndicator=document.createElement('DIV');this.dropTargetIndicator.style.zIndex=240000;this.dropTargetIndicator.style.position='absolute';this.dropTargetIndicator.style.display='none';var img=document.createElement('IMG');img.src=DHTMLSuite.configObj.imagePath+'drag-drop-tree/'+'dragDrop_ind1.gif';img.id='dragDropIndicatorImage';this.dropTargetIndicator.appendChild(img);document.body.appendChild(this.dropTargetIndicator)},__getDepthOfABranchInTheTree:function(obj,direction,stopAtObject){var countLevels=0;if(direction=='up'){while(obj.parentNode&&obj.parentNode!=stopAtObject){obj=obj.parentNode;if(obj.tagName=='UL')countLevels=countLevels/1+1} +return countLevels} +if(direction=='down'){var subObjects=obj.getElementsByTagName('LI');for(var no=0;no'} +if(this.waitMessage){waitMessageToShow=waitMessageToShow+'
'+this.waitMessage+'
'} +if(this.waitMessage!=null&&this.waitImage!=null){try{if(waitMessageToShow.length>0)document.getElementById(divId).innerHTML=waitMessageToShow}catch(e){}} +waitMessageToShow=false;var ajaxIndex=this.ajaxObjects.length;try{this.ajaxObjects[ajaxIndex]=new sack()}catch(e){alert('Could not create ajax object. Please make sure that ajax.js is included')} +if(url.indexOf('?')>=0){this.ajaxObjects[ajaxIndex].method='GET';var string=url.substring(url.indexOf('?'));url=url.replace(string,'');string=string.replace('?','');var items=string.split(/&/g);for(var no=0;no'}} +DHTMLSuite.sliderObjects=new Array();DHTMLSuite.indexOfCurrentlyActiveSlider=false;DHTMLSuite.slider_generalMouseEventsAdded=false;DHTMLSuite.slider=function(){var width;var height;var targetObj;var sliderWidth;var sliderDirection;var functionToCallOnChange;var layoutCss;var sliderMaxValue;var sliderMinValue;var initialValue;var sliderSize;var directionOfPointer;var slideInProcessTimer;var indexThisSlider;var numberOfSteps;var stepLinesVisibility;var slide_event_pos;var slide_start_pos;var sliderHandleImg;var sliderName;var sliderValueReversed;this.sliderWidth=9;this.layoutCss='slider.css';this.sliderDirection='hor';this.width=0;this.height=0;this.sliderMaxValue=100;this.sliderMinValue=0;this.initialValue=0;this.targetObj=false;this.directionOfPointer='up';this.slideInProcessTimer=-1;this.sliderName='';this.numberOfSteps=false;this.stepLinesVisibility=true;this.sliderValueReversed=false;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} +var objectIndex;this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this} +DHTMLSuite.slider.prototype={init:function(){if(!this.targetObj){alert('Error!-No target for slider specified');return} +this.__setWidthAndHeightDynamically();DHTMLSuite.commonObj.loadCSS(this.layoutCss);this.__createSlider();if(!document.documentElement.onselectstart)document.documentElement.onselectstart=function(){return DHTMLSuite.commonObj.__isTextSelOk()}},setSliderTarget:function(targetRef){targetRef=DHTMLSuite.commonObj.getEl(targetRef);this.targetObj=targetRef},setSliderDirection:function(newDirection){newDirection=newDirection+'';newDirection=newDirection.toLowerCase();if(newDirection!='hor'&&newDirection!='ver'){alert('Invalid slider direction-possible values: "hor" or "ver"');return} +this.sliderDirection=newDirection},setSliderWidth:function(newWidth){newWidth=newWidth+'';if(newWidth.indexOf('%')==-1)newWidth=newWidth+'px';this.width=newWidth},setSliderHeight:function(newHeight){newHeight=newHeight+'';if(newHeight.indexOf('%')==-1)newHeight=newHeight+'px';this.height=height},setSliderReversed:function(){this.sliderValueReversed=true},setOnChangeEvent:function(nameOfFunction){this.functionToCallOnChange=nameOfFunction},setSliderMaxValue:function(newMaxValue){this.sliderMaxValue=newMaxValue},setSliderMinValue:function(newMinValue){this.sliderMinValue=newMinValue},setSliderName:function(nameOfSlider){this.sliderName=nameOfSlider},setLayoutCss:function(nameOfNewCssFile){this.layoutCss=nameOfNewCssFile},setInitialValue:function(newInitialValue){this.initialValue=newInitialValue},setSliderPointerDirection:function(directionOfPointer){this.directionOfPointer=directionOfPointer},setSliderValue:function(newValue){var position=Math.floor((newValue/this.sliderMaxValue)*this.sliderSize);if(this.sliderDirection=='hor'){this.sliderHandleImg.style.left=position+'px'}else{this.sliderHandleImg.style.top=position+'px'}},setNumberOfSliderSteps:function(numberOfSteps){this.numberOfSteps=numberOfSteps},setStepLinesVisible:function(visible){this.stepLinesVisibility=visible},__setWidthAndHeightDynamically:function(){if(!this.width||this.width==0)this.width=this.targetObj.clientWidth+'';if(!this.height||this.height==0)this.height=this.targetObj.clientHeight+'';if(!this.width||this.width==0)this.width=this.targetObj.offsetWidth+'';if(!this.height||this.height==0)this.height=this.targetObj.offsetHeight+'';if(this.width==0)return;if(this.height==0)return;if(this.width.indexOf('px')==-1&&this.width.indexOf('%')==-1)this.width=this.width+'px';if(this.height.indexOf('px')==-1&&this.height.indexOf('%')==-1)this.height=this.height+'px'},__createSlider:function(initWidth){if(this.targetObj.clientWidth==0||initWidth==0){var timeoutTime=100;setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+this.objectIndex+'].__createSlider('+this.targetObj.clientWidth+')',timeoutTime);return} +this.__setWidthAndHeightDynamically();this.indexThisSlider=DHTMLSuite.sliderObjects.length;DHTMLSuite.sliderObjects[this.indexThisSlider]=this;window.refToThisObject=this;var div=document.createElement('DIV');div.style.width=this.width;div.style.cursor='default';div.style.height=this.height;div.style.position='relative';div.id='sliderNumber'+this.indexThisSlider;div.onmousedown=this.__setPositionFromClick;DHTMLSuite.commonObj.__addEventEl(div);this.targetObj.appendChild(div);var sliderObj=document.createElement('DIV');if(this.sliderDirection=='hor'){sliderObj.className='DHTMLSuite_slider_horizontal';sliderObj.style.width=div.clientWidth+'px';this.sliderSize=div.offsetWidth-this.sliderWidth;var sliderHandle=document.createElement('IMG');var srcHandle='slider_handle_down.gif';sliderHandle.style.bottom='2px';if(this.directionOfPointer=='up'){srcHandle='slider_handle_up.gif';sliderHandle.style.bottom='0px'} +sliderHandle.src=DHTMLSuite.configObj.imagePath+'slider/'+srcHandle;div.appendChild(sliderHandle);var leftPos;if(this.sliderValueReversed){leftPos=Math.round(((this.sliderMaxValue-this.initialValue)/this.sliderMaxValue)*this.sliderSize)-1}else{leftPos=Math.round((this.initialValue/this.sliderMaxValue)*this.sliderSize)} +sliderHandle.style.left= leftPos+'px'}else{sliderObj.className='DHTMLSuite_slider_vertical';sliderObj.style.height=div.clientHeight+'px';this.sliderSize=div.clientHeight-this.sliderWidth;var sliderHandle=document.createElement('IMG');var srcHandle='slider_handle_right.gif';sliderHandle.style.left='0px';if(this.directionOfPointer=='left'){srcHandle='slider_handle_left.gif';sliderHandle.style.left='0px'} +sliderHandle.src=DHTMLSuite.configObj.imagePath+'slider/'+srcHandle;div.appendChild(sliderHandle);var topPos;if(!this.sliderValueReversed){topPos=Math.floor(((this.sliderMaxValue-this.initialValue)/this.sliderMaxValue)*this.sliderSize)}else{topPos=Math.floor((this.initialValue/this.sliderMaxValue)*this.sliderSize)} +sliderHandle.style.top=topPos+'px'} +sliderHandle.id='sliderForObject'+this.indexThisSlider;sliderHandle.style.position='absolute';sliderHandle.style.zIndex=5;sliderHandle.onmousedown=this.__initializeSliderDrag;sliderHandle.ondragstart=function(){return false};sliderHandle.onselectstart=function(){return false};DHTMLSuite.commonObj.__addEventEl(sliderHandle);this.sliderHandleImg=sliderHandle;if(!DHTMLSuite.slider_generalMouseEventsAdded){DHTMLSuite.commonObj.addEvent(document.documentElement,"mousemove",this.__moveSlider);DHTMLSuite.commonObj.addEvent(document.documentElement,"mouseup",this.__stopSlideProcess);DHTMLSuite.slider_generalMouseEventsAdded=true} +sliderObj.innerHTML='';div.appendChild(sliderObj);if(this.numberOfSteps&&this.stepLinesVisibility){var stepSize=this.sliderSize/this.numberOfSteps;for(var no=0;no<=this.numberOfSteps;no++){var lineDiv=document.createElement('DIV');lineDiv.style.position='absolute';lineDiv.innerHTML='';div.appendChild(lineDiv);if(this.sliderDirection=='hor'){lineDiv.className='DHTMLSuite_smallLines_vertical';lineDiv.style.left=Math.floor((stepSize*no)+(this.sliderWidth/2))+'px'}else{lineDiv.className='DHTMLSuite_smallLines_horizontal';lineDiv.style.top=Math.floor((stepSize*no)+(this.sliderWidth/2))+'px';lineDiv.style.left='14px'}}}},__initializeSliderDrag:function(e){if(document.all)e=event;DHTMLSuite.commonObj.__setTextSelOk(false);var numIndex=this.id.replace(/[^0-9]/gi,'');var sliderObj=DHTMLSuite.sliderObjects[numIndex];DHTMLSuite.indexOfCurrentlyActiveSlider=numIndex;sliderObj.slideInProcessTimer=0;if(sliderObj.sliderDirection=='hor'){sliderObj.slide_event_pos=e.clientX;sliderObj.slide_start_pos=this.style.left.replace('px','')/1}else{sliderObj.slide_event_pos=e.clientY;sliderObj.slide_start_pos=this.style.top.replace('px','')/1} +sliderObj.__waitBeforeSliderDragStarts();return false},__setPositionFromClick:function(e){if(document.all)e=event;if(e.target)srcEvent=e.target;else if(e.srcElement)srcEvent=e.srcElement;if(srcEvent.nodeType==3) +srcEvent=srcEvent.parentNode;if(srcEvent.tagName!='DIV')return;var numIndex=this.id.replace(/[^0-9]/gi,'');var sliderObj=DHTMLSuite.sliderObjects[numIndex];if(sliderObj.numberOfSteps){modValue=sliderObj.sliderSize/sliderObj.numberOfSteps} +if(sliderObj.sliderDirection=='hor'){var handlePos=(e.clientX-DHTMLSuite.commonObj.getLeftPos(this)- Math.ceil(sliderObj.sliderWidth/2))}else{var handlePos=(e.clientY-DHTMLSuite.commonObj.getTopPos(this)- Math.ceil(sliderObj.sliderWidth/2))} +if(sliderObj.numberOfSteps){var mod=handlePos % modValue;if(mod>(modValue/2))mod=modValue-mod;else mod*=-1;handlePos=handlePos+mod} +if(handlePos<0)handlePos=0;if(handlePos > sliderObj.sliderSize)handlePos=sliderObj.sliderSize;if(sliderObj.sliderDirection=='hor'){sliderObj.sliderHandleImg.style.left=handlePos+'px';if(!sliderObj.sliderValueReversed){returnValue=Math.round((handlePos/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}else{returnValue=Math.round(((sliderObj.sliderSize-handlePos)/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}}else{sliderObj.sliderHandleImg.style.top=handlePos+'px';if(sliderObj.sliderValueReversed){returnValue=Math.round((handlePos/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}else{returnValue=Math.round(((sliderObj.sliderSize-handlePos)/sliderObj.sliderSize)*(sliderObj.sliderMaxValue-sliderObj.sliderMinValue))}} +returnValue=returnValue+sliderObj.sliderMinValue;if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange+'('+returnValue+',"'+sliderObj.sliderName+'","click")');DHTMLSuite.indexOfCurrentlyActiveSlider=numIndex;sliderObj.slideInProcessTimer=10;if(sliderObj.sliderDirection=='hor'){sliderObj.slide_event_pos=e.clientX;sliderObj.slide_start_pos=handlePos}else{sliderObj.slide_event_pos=e.clientY;sliderObj.slide_start_pos=handlePos} +DHTMLSuite.commonObj.__setTextSelOk(false)},__waitBeforeSliderDragStarts:function(){if(this.slideInProcessTimer<10&&this.slideInProcessTimer>=0){this.slideInProcessTimer+=2;window.refToThisSlider=this;setTimeout('window.refToThisSlider.__waitBeforeSliderDragStarts()',5)}},__moveSlider:function(e){if(DHTMLSuite.indexOfCurrentlyActiveSlider===false)return;var sliderObj=DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider];if(document.all)e=event;if(sliderObj.slideInProcessTimer<10)return;var returnValue=sliderObj.__getSliderValue(e);if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange+'('+returnValue+',"'+sliderObj.sliderName+'","move")')},__getSliderValue:function(e){var returnValue;if(this.numberOfSteps){modValue=this.sliderSize/this.numberOfSteps} +if(this.sliderDirection=='hor'){var handlePos=e.clientX-this.slide_event_pos+this.slide_start_pos}else{var handlePos=e.clientY-this.slide_event_pos+this.slide_start_pos} +if(this.numberOfSteps){var mod=handlePos % modValue;if(mod>(modValue/2))mod=modValue-mod;else mod*=-1;handlePos=handlePos+mod} +if(handlePos<0)handlePos=0;if(handlePos > this.sliderSize)handlePos=this.sliderSize;if(this.sliderDirection=='hor'){this.sliderHandleImg.style.left=handlePos+'px';if(!this.sliderValueReversed){returnValue=Math.round((handlePos/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}else{returnValue=Math.round(((this.sliderSize-handlePos)/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}}else{this.sliderHandleImg.style.top=handlePos+'px';if(this.sliderValueReversed){returnValue=Math.round((handlePos/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}else{returnValue=Math.round(((this.sliderSize-handlePos)/this.sliderSize)*(this.sliderMaxValue-this.sliderMinValue))}} +returnValue=returnValue+this.sliderMinValue;return returnValue},__stopSlideProcess:function(e){if(document.all)e=event;DHTMLSuite.commonObj.__setTextSelOk(true);if(!DHTMLSuite.indexOfCurrentlyActiveSlider)return;var sliderObj=DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider];sliderObj.slideInProcessTimer=-1;var returnValue=sliderObj.__getSliderValue(e);if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange+'('+returnValue+',"'+sliderObj.sliderName+'","mouseup")')}} +DHTMLSuite.modalMessage=function(props){var url;var htmlOfModalMessage;var domRef;var divs_transparentDiv;var divs_content;var iframeEl;var layoutCss;var width;var height;var isModal;var existingBodyOverFlowStyle;var dynContentObj;var cssClassOfMessageBox;var shadowDivVisible;var shadowOffset;var objectIndex;this.url='';this.htmlOfModalMessage='';this.layoutCss='modal-message.css';this.height=200;this.width=400;this.cssClassOfMessageBox=false;this.shadowDivVisible=true;this.shadowOffset=5;this.isModal=true;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} +this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this;var ind=this.objectIndex;DHTMLSuite.commonObj.addEvent(window,"resize",function(){DHTMLSuite.variableStorage.arrayDSObjects[ind].__resizeTransparentDiv()});if(props)this.__setInitialProps(props)} +DHTMLSuite.modalMessage.prototype={__setInitialProps:function(props){if(props.url)this.setSource(props.url);if(props.htmlOfModalMessage)this.setHtmlContent(props.htmlOfModalMessage);if(props.domRef)this.setDomReference(props.domRef);if(props.width)this.width=props.width;if(props.height)this.height=props.height;if(props.cssClassOfMessageBox)this.cssClassOfMessageBox=props.cssClassOfMessageBox;if(props.shadowOffset)this.shadowOffset=props.shadowOffset;if(props.shadowDivVisible)this.shadowDivVisible=props.shadowDivVisible;if(props.isModal||props.isModal===false||props.isModal===0)this.isModal=props.isModal;if(props.waitMessage)this.setWaitMessage(waitMessage)},setIsModal:function(isModal){this.isModal=isModal},setSource:function(urlOfSource){if(urlOfSource)this.__clearProperties();this.url=urlOfSource},setHtmlContent:function(newHtmlContent){if(newHtmlContent)this.__clearProperties();this.htmlOfModalMessage=newHtmlContent},setDomReference:function(domRef){if(domRef)this.__clearProperties();if(domRef)domRef=DHTMLSuite.commonObj.getEl(domRef);if(domRef){domRef=domRef.cloneNode(true)} +this.domRef=domRef},setSize:function(width,height){if(width)this.width=width;if(height)this.height=height},setCssClassMessageBox:function(newCssClass){this.cssClassOfMessageBox=newCssClass;if(this.divs_content){if(this.cssClassOfMessageBox) +this.divs_content.className=this.cssClassOfMessageBox;else +this.divs_content.className='modalDialog_contentDiv'}},setShadowOffset:function(newShadowOffset){this.shadowOffset=newShadowOffset +},setWaitMessage:function(newMessage){if(!this.dynContentObj){try{this.dynContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include dhtmlSuite-dynamicContent.js')}} +this.dynContentObj.setWaitMessage(newMessage)},setWaitImage:function(newImage){if(!this.dynContentObj){try{this.dynContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include dhtmlSuite-dynamicContent.js')}} +this.dynContentObj.setWaitImage(newImage)},setCache:function(cacheStatus){if(!this.dynContentObj){try{this.dynContentObj=new DHTMLSuite.dynamicContent()}catch(e){alert('Include dhtmlSuite-dynamicContent.js')}} +this.dynContentObj.setCache(cacheStatus)},display:function(){var ind=this.objectIndex;if(!this.divs_transparentDiv){DHTMLSuite.commonObj.loadCSS(this.layoutCss);this.__createDivElements()} +this.__resizeAndPositionDivElements();if(this.isModal){this.divs_transparentDiv.style.display='block'}else{this.divs_transparentDiv.style.display='none'} +this.divs_content.style.display='block';this.divs_shadow.style.display='block';if(this.iframeEl){setTimeout('DHTMLSuite.variableStorage.arrayDSObjects['+ind+'].iframeEl.style.display="block"',150)} +this.__resizeAndPositionDivElements();window.refToThisModalBoxObj=this;setTimeout('window.refToThisModalBoxObj.__resizeAndPositionDivElements()',100);this.__addHTMLContent()},setShadowDivVisible:function(visible){this.shadowDivVisible=visible},close:function(){document.documentElement.style.overflow='';this.divs_transparentDiv.style.display='none';this.divs_content.style.display='none';this.divs_shadow.style.display='none';if(this.iframeEl)this.iframeEl.style.display='none'},__clearProperties:function(){if(this.domRef)DHTMLSuite.discardElement(this.domRef);this.domRef=null;this.url=false;this.htmlOfModalMessage=false},__createDivElements:function(){this.divs_transparentDiv=document.createElement('DIV');this.divs_transparentDiv.className='DHTMLSuite_modalDialog_transparentDivs';this.divs_transparentDiv.style.left='0px';this.divs_transparentDiv.style.top='0px';this.divs_transparentDiv.id='transparentDiv';document.body.appendChild(this.divs_transparentDiv);if(!document.getElementById('DHTMLSuite_modalBox_contentDiv')){this.divs_content=document.createElement('DIV');this.divs_content.className='DHTMLSuite_modalDialog_contentDiv';this.divs_content.id='DHTMLSuite_modalBox_contentDiv';document.body.appendChild(this.divs_content)}else{this.divs_content=document.getElementById('DHTMLSuite_modalBox_contentDiv')} +this.divs_shadow=document.createElement('DIV');this.divs_shadow.className='DHTMLSuite_modalDialog_contentDiv_shadow';document.body.appendChild(this.divs_shadow);if(DHTMLSuite.clientInfoObj.isMSIE){this.iframeEl=document.createElement('';this.formRef.method=this.method;this.formRef.action=this.action;this.formRef.target=this.iframeName;if(!this.formRef.enctype)this.formRef.enctype='multipart/form-data'},__getIframeResponse:function(){if(this.responseEl){if(this.responseFile){if(!this.responseEl.id)this.responseEl.id='DHTMLSuite_formResponse'+DHTMLSuite.getUniqueId();var dynContent=new DHTMLSuite.dynamicContent();dynContent.loadContent(this.responseEl.id,this.responseFile)}else{this.responseEl.innerHTML=self.frames[this.iframeName].document.body.innerHTML;DHTMLSuite.commonObj.__evaluateJs(this.responseEl);DHTMLSuite.commonObj.__evaluateCss(this.responseEl)}} +this.coverDiv.style.display='none';this.__handleCallback('onComplete')},__positionCoverDiv:function(){if(!this.responseEl)return;try{var st=this.coverDiv.style;st.left=DHTMLSuite.commonObj.getLeftPos(this.responseEl)+'px';st.top=DHTMLSuite.commonObj.getTopPos(this.responseEl)+'px';st.width=this.responseEl.offsetWidth+'px';st.height=this.responseEl.offsetHeight+'px';st.display='block'}catch(e){}},__createCoverDiv:function(){if(this.coverDiv)return;this.coverDiv=document.createElement('DIV');var el=this.coverDiv;el.style.overflow='hidden';el.style.zIndex=1000;el.style.position='absolute';document.body.appendChild(el);var innerDiv=document.createElement('DIV');innerDiv.style.width='105%';innerDiv.style.height='105%';innerDiv.className='DHTMLSuite_formCoverDiv';innerDiv.style.opacity='0.2';innerDiv.style.filter='alpha(opacity=20)';el.appendChild(innerDiv);var ajaxLoad=document.createElement('DIV');ajaxLoad.className='DHTMLSuite_formCoverDiv_ajaxLoader';el.appendChild(ajaxLoad)},__createSackObject:function(ajaxIndex){var ind=this.objectIndex;this.sackObj[ajaxIndex]=new sack();this.sackObj[ajaxIndex].requestFile=this.action;this.sackObj[ajaxIndex].method=this.method;this.sackObj[ajaxIndex].onCompletion=function(){DHTMLSuite.variableStorage.arrayDSObjects[ind].__getResponse(ajaxIndex)}},__getResponse:function(ajaxIndex){if(this.responseEl){if(this.responseFile){if(!this.responseEl.id)this.responseEl.id='DHTMLSuite_formResponse'+DHTMLSuite.getUniqueId();var dynContent=new DHTMLSuite.dynamicContent();dynContent.loadContent(this.responseEl.id,this.responseFile)}else{this.responseEl.innerHTML=this.sackObj[ajaxIndex].response;DHTMLSuite.commonObj.__evaluateJs(this.responseEl);DHTMLSuite.commonObj.__evaluateCss(this.responseEl)}} +this.coverDiv.style.display='none';this.sackObj[ajaxIndex]=null;this.__handleCallback('onComplete')},__populateSack:function(ajaxIndex){var els=this.formUtil.getValuesAsArray(this.formRef);for(var prop in els){if(DHTMLSuite.commonObj.isArray(els[prop])){for(var no=0;no=0){name=prop.replace('[','['+no)} +this.sackObj[ajaxIndex].setVar(name,els[prop][no])}}else{this.sackObj[ajaxIndex].setVar(prop,els[prop])}}},__setInitProperties:function(props){if(props.formRef)this.formRef=DHTMLSuite.commonObj.getEl(props.formRef);if(props.method)this.method=props.method;if(props.responseEl)this.responseEl=DHTMLSuite.commonObj.getEl(props.responseEl);if(props.action)this.action=props.action;if(props.responseFile)this.responseFile=props.responseFile;if(props.callbackOnComplete)this.callbackOnComplete=props.callbackOnComplete;if(!this.action)this.action=this.formRef.action;if(!this.method)this.method=this.formRef.method},__handleCallback:function(action){var callbackString='';switch(action){case "onComplete":callbackString=this.callbackOnComplete;break} +if(callbackString){if(callbackString.indexOf('(')==-1)callbackString=callbackString+'("'+this.formRef.name+'")';eval(callbackString)}}} +DHTMLSuite.autoComplete=function(){var layoutCss;var ajaxBox_offsetX;var ajaxBox_offsetY;var minimumLettersBeforeLookup;var ajax_list_currentLetters;var ajax_list_cachedLists +var ajax_optionDiv;var ajax_list_MSIE;var ajax_list_activeItem;var ajax_list_objects;var ajax_list_activeInput;var ajax_list_activeItem;var ajax_list_optionDivFirstItem +var ajax_optionDiv;var ajax_optionDiv_iframe;this.layoutCss='auto-complete.css';this.ajaxBox_offsetX=0;this.ajaxBox_offsetY=0;this.ajax_list_currentLetters=new Array();this.ajax_list_cachedLists=new Array();this.ajax_optionDiv=false;this.ajax_list_MSIE=false;if(navigator.userAgent.indexOf('MSIE')>=0&&navigator.userAgent.indexOf('Opera')<0) +this.ajax_list_MSIE=true;this.ajax_list_activeItem;this.ajax_list_objects=new Array();this.ajax_list_activeInput=false;this.ajax_list_activeItem;this.ajax_list_optionDivFirstItem=false;this.ajax_optionDiv=false;this.ajax_optionDiv_iframe=false;var ajax_list_MSIE=false;if(navigator.userAgent.indexOf('MSIE')>=0&&navigator.userAgent.indexOf('Opera')<0)ajax_list_MSIE=true;this.minimumLettersBeforeLookup=1;try{if(!standardObjectsCreated)DHTMLSuite.createStandardObjects()}catch(e){alert('Include the dhtmlSuite-common.js file')} +this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length;;DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this;document.body.setAttribute("objectIndex",this.objectIndex);DHTMLSuite.commonObj.loadCSS(this.layoutCss)} +DHTMLSuite.autoComplete.prototype={add:function(inputObjId,externalFile){var refObject=DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex];eval("document.getElementById('"+inputObjId+"').onkeyup=function(e){refObject.__showOptions(e,'"+inputObjId+"','"+externalFile+"')};");DHTMLSuite.commonObj.__addEventEl(document.getElementById(inputObjId))},setLayoutCss:function(newCssFileName){this.layoutCss=newCssFileName},__showOptions:function(e,inputObjId,externalFile){var inputObj=document.getElementById(inputObjId);var ind=this.objectIndex;if(document.all)e=event;if(e.keyCode==13||e.keyCode==9)return;if(this.ajax_list_currentLetters[inputObj.name]==inputObj.value)return;if(!this.ajax_list_cachedLists[inputObj.id])this.ajax_list_cachedLists[inputObj.id]=new Array();this.ajax_list_currentLetters[inputObj.name]=inputObj.value;if(!this.ajax_optionDiv){this.ajax_optionDiv=document.createElement('DIV');this.ajax_optionDiv.id='ajax_listOfOptions';document.body.appendChild(this.ajax_optionDiv);if(this.ajax_list_MSIE){this.ajax_optionDiv_iframe=document.createElement('IFRAME');this.ajax_optionDiv_iframe.border='0';this.ajax_optionDiv_iframe.style.width=this.ajax_optionDiv.clientWidth+'px';this.ajax_optionDiv_iframe.style.height=this.ajax_optionDiv.clientHeight+'px';this.ajax_optionDiv_iframe.id='ajax_listOfOptions_iframe';document.body.appendChild(this.ajax_optionDiv_iframe)} +var allInputs=document.getElementsByTagName('INPUT');for(var no=0;no this.ajax_optionDiv.offsetHeight){this.ajax_optionDiv.scrollTop=this.ajax_list_activeItem.offsetTop-this.ajax_optionDiv.offsetHeight+this.ajax_list_activeItem.offsetHeight+2 } +if(this.ajax_list_activeItem.offsetTop < this.ajax_optionDiv.scrollTop){this.ajax_optionDiv.scrollTop=0}}},__ajaxOptionResize:function(inputObj){this.ajax_optionDiv.style.top =(this.__ajaxGetTopPos(inputObj)+inputObj.offsetHeight+this.ajaxBox_offsetY)+'px';this.ajax_optionDiv.style.left=(this.__ajaxGetLeftPos(inputObj)+this.ajaxBox_offsetX)+'px';if(this.ajax_optionDiv_iframe){this.ajax_optionDiv_iframe.style.left=this.ajax_optionDiv.style.left;this.ajax_optionDiv_iframe.style.top=this.ajax_optionDiv.style.top}},__ajaxGetTopPos:function(inputObj){var returnValue=inputObj.offsetTop;while((inputObj=inputObj.offsetParent)!=null){returnValue+= inputObj.offsetTop} +return returnValue},__ajaxGetLeftPos:function(inputObj){var returnValue=inputObj.offsetLeft;while((inputObj=inputObj.offsetParent)!=null)returnValue+= inputObj.offsetLeft;return returnValue},__ajaxOptionListShowContent:function(ajaxIndex,inputObj){var letters=inputObj.value;var content=this.ajax_list_objects[ajaxIndex].response;var elements=content.split('|');this.ajax_list_cachedLists[inputObj.id][letters.toLowerCase()]=elements;this.__ajaxOptionListBuildList(letters,inputObj.id)},__ajaxOptionListBuildList:function(letters,inputObjId){var ind=this.objectIndex;this.ajax_optionDiv.innerHTML='';this.ajax_list_activeItem=false;if(this.ajax_list_cachedLists[inputObjId][letters.toLowerCase()].length<=1){this.__ajaxOptionsHide();return} +this.ajax_list_optionDivFirstItem=false;var optionsAdded=false;for(var no=0;no1)targetObj.options[targetObj.options.length]=new Option(option_array[0].trim(),option_array[1].trim())}}} \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications.js b/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications.js index 6047165..3e7bdef 100755 --- a/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications.js +++ b/ext/dhtml-suite-for-applications/js/dhtml-suite-for-applications.js @@ -1,24808 +1,24808 @@ -/*[FILE_START:dhtmlSuite-common.js] */ -/************************************************************************************************************ - @fileoverview - DHTML Suite for Applications. - Copyright (C) 2006 Alf Magne Kalleland(post@dhtmlgoodies.com)
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-
- www.dhtmlgoodies.com
- Alf Magne Kalleland
- -************************************************************************************************************/ - -/** - * - * @package DHTMLSuite for applications - * @copyright Copyright © 2006, www.dhtmlgoodies.com - * @author Alf Magne Kalleland - */ - -/****** -Some prototypes: -**/ - - // Creating a trim method -if(!String.trim)String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); }; -var DHTMLSuite_funcs = new Object(); -if(!window.DHTML_SUITE_THEME)var DHTML_SUITE_THEME = 'blue'; -if(!window.DHTML_SUITE_THEME_FOLDER)var DHTML_SUITE_THEME_FOLDER = '../themes/'; -if(!window.DHTML_SUITE_JS_FOLDER)var DHTML_SUITE_JS_FOLDER = '../js/separateFiles/'; - -/************************************************************************************************************ -* -* Global variables -* -************************************************************************************************************/ - - // {{{ DHTMLSuite.createStandardObjects() -/** - * Create objects used by all scripts - * - * @public - */ - -var DHTMLSuite = new Object(); - -var standardObjectsCreated = false; // The classes below will check this variable, if it is false, default help objects will be created -DHTMLSuite.eventEls = new Array(); // Array of elements that has been assigned to an event handler. - -var widgetDep = new Object(); - // Widget dependencies -widgetDep['formValidator'] = ['dhtmlSuite-formUtil.js']; // Form validator widget -widgetDep['paneSplitter'] = ['dhtmlSuite-paneSplitter.js','dhtmlSuite-paneSplitterModel.js','dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['menuBar'] = ['dhtmlSuite-menuBar.js','dhtmlSuite-menuItem.js','dhtmlSuite-menuModel.js']; -widgetDep['windowWidget'] = ['dhtmlSuite-windowWidget.js','dhtmlSuite-resize.js','dhtmlSuite-dragDropSimple.js','ajax.js','dhtmlSuite-dynamicContent.js']; -widgetDep['colorWidget'] = ['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js']; -widgetDep['colorSlider'] = ['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js','dhtmlSuite-slider.js']; -widgetDep['colorPalette'] = ['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js']; -widgetDep['calendar'] = ['dhtmlSuite-calendar.js','dhtmlSuite-dragDropSimple.js']; -widgetDep['dragDropTree'] = ['dhtmlSuite-dragDropTree.js']; -widgetDep['slider'] = ['dhtmlSuite-slider.js']; -widgetDep['dragDrop'] = ['dhtmlSuite-dragDrop.js']; -widgetDep['imageEnlarger'] = ['dhtmlSuite-imageEnlarger.js','dhtmlSuite-dragDropSimple.js']; -widgetDep['imageSelection'] = ['dhtmlSuite-imageSelection.js']; -widgetDep['floatingGallery'] = ['dhtmlSuite-floatingGallery.js','dhtmlSuite-mediaModel.js']; -widgetDep['contextMenu'] = ['dhtmlSuite-contextMenu.js','dhtmlSuite-menuBar.js','dhtmlSuite-menuItem.js','dhtmlSuite-menuModel.js']; -widgetDep['dynamicContent'] = ['dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['textEdit'] = ['dhtmlSuite-textEdit.js','dhtmlSuite-textEditModel.js','dhtmlSuite-listModel.js']; -widgetDep['listModel'] = ['dhtmlSuite-listModel.js']; -widgetDep['resize'] = ['dhtmlSuite-resize.js']; -widgetDep['dragDropSimple'] = ['dhtmlSuite-dragDropSimple.js']; -widgetDep['dynamicTooltip'] = ['dhtmlSuite-dynamicTooltip.js','dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['modalMessage'] = ['dhtmlSuite-modalMessage.js','dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['tableWidget'] = ['dhtmlSuite-tableWidget.js','ajax.js']; -widgetDep['progressBar'] = ['dhtmlSuite-progressBar.js']; -widgetDep['tabView'] = ['dhtmlSuite-tabView.js','dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['infoPanel'] = ['dhtmlSuite-infoPanel.js','dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['form'] = ['dhtmlSuite-formUtil.js','dhtmlSuite-dynamicContent.js','ajax.js']; -widgetDep['autoComplete']=['dhtmlSuite-autoComplete.js','ajax.js']; -widgetDep['chainedSelect']=['dhtmlSuite-chainedSelect.js','ajax.js']; - -var depCache = new Object(); - -DHTMLSuite.include = function(widget){ - if(!widgetDep[widget]){ - alert('Cannot find the files for widget ' + widget + '. Please verify that the name is correct'); - return; - } - var files = widgetDep[widget]; - for(var no=0;no'); - document.write(''); - depCache[files[no]] = true; - } - } -} - -DHTMLSuite.discardElement = function(element) { - element = DHTMLSuite.commonObj.getEl(element); - var gBin = document.getElementById('IELeakGBin'); - if (!gBin) { - gBin = document.createElement('DIV'); - gBin.id = 'IELeakGBin'; - gBin.style.display = 'none'; - document.body.appendChild(gBin); - } - // move the element to the garbage bin - gBin.appendChild(element); - gBin.innerHTML = ''; -} - -DHTMLSuite.createStandardObjects = function(){ - DHTMLSuite.clientInfoObj = new DHTMLSuite.clientInfo(); // Create browser info object - DHTMLSuite.clientInfoObj.init(); - if(!DHTMLSuite.configObj){ // If this object isn't allready created, create it. - DHTMLSuite.configObj = new DHTMLSuite.config(); // Create configuration object. - DHTMLSuite.configObj.init(); - } - DHTMLSuite.commonObj = new DHTMLSuite.common(); // Create configuration object. - DHTMLSuite.variableStorage = new DHTMLSuite.globalVariableStorage();; // Create configuration object. - DHTMLSuite.commonObj.init(); - DHTMLSuite.domQueryObj = new DHTMLSuite.domQuery(); - - DHTMLSuite.commonObj.addEvent(window,'unload',function(){ DHTMLSuite.commonObj.__clearMemoryGarbage(); }); - - standardObjectsCreated = true; -} - -/************************************************************************************************************ -* Configuration class used by most of the scripts -* -* Created: August, 19th, 2006 -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class Store global variables/configurations used by the classes below. Example: If you want to -* change the path to the images used by the scripts, change it here. An object of this -* class will always be available to the other classes. The name of this object is -* "DHTMLSuite.configObj".

-* -* If you want to create an object of this class manually, remember to name it "DHTMLSuite.configObj" -* This object should then be created before any other objects. This is nescessary if you want -* the other objects to use the values you have put into the object.
-* @version 1.0 -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ -DHTMLSuite.config = function(){ - var imagePath; // Path to images used by the classes. - var cssPath; // Path to CSS files used by the DHTML suite. - - var defaultCssPath; - var defaultImagePath; -} - -DHTMLSuite.config.prototype = { - // {{{ init() - /** - * Initializes the config object - the config class is used to store global properties used by almost all widgets - * - * @public - */ - init : function(){ - this.imagePath = DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/images/'; // Path to images - this.cssPath = DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/css/'; // Path to images - - this.defaultCssPath = this.cssPath; - this.defaultImagePath = this.imagePath; - - } - // }}} - , - // {{{ setCssPath() - /** - * This method will save a new CSS path, i.e. where the css files of the dhtml suite are located(the folder). - * This method is rarely used. Default value is the variable DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/css', - * which means that the css path is set dynamically based on which theme you choose. - * - * @param string newCssPath = New path to css files(folder - remember to have a slash(/) at the end) - * @public - */ - - setCssPath : function(newCssPath){ - this.cssPath = newCssPath; - } - // }}} - , - // {{{ resetCssPath() - /** - * @deprecated - * Resets css path back to default value which is ../css_dhtmlsuite/ - * This method is deprecated. - * - * @public - */ - resetCssPath : function(){ - this.cssPath = this.defaultCssPath; - } - // }}} - , - // {{{ resetImagePath() - /** - * @deprecated - * - * Resets css path back to default path which is DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/css' - * This method is deprecated. - * @public - */ - resetImagePath : function(){ - this.imagePath = this.defaultImagePath; - } - // }}} - , - // {{{ setImagePath() - /** - * This method will save a new image file path, i.e. where the image files used by the dhtml suite ar located - * - * @param string newImagePath = New path to image files (remember to have a slash(/) at the end) - * @public - */ - setImagePath : function(newImagePath){ - this.imagePath = newImagePath; - } - // }}} -} - -DHTMLSuite.globalVariableStorage = function(){ - var menuBar_highlightedItems; // Array of highlighted menu bar items - this.menuBar_highlightedItems = new Array(); - - var arrayDSObjects; // Array of objects of class menuItem. - var arrayOfDhtmlSuiteObjects; - this.arrayDSObjects = new Array(); - this.arrayOfDhtmlSuiteObjects = this.arrayDSObjects; - var ajaxObjects; - this.ajaxObjects = new Array(); -} - -DHTMLSuite.globalVariableStorage.prototype = { - -} - -/************************************************************************************************************ -* A class with general methods used by most of the scripts -* -* Created: August, 19th, 2006 -* Purpose of class: A class containing common method used by one or more of the gui classes below, -* example: loadCSS. -* An object("DHTMLSuite.commonObj") of this class will always be available to the other classes. -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class A class containing common method used by one or more of the gui classes below, example: loadCSS. An object("DHTMLSuite.commonObj") of this class will always be available to the other classes. -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.common = function(){ - var loadedCSSFiles; // Array of loaded CSS files. Prevent same CSS file from being loaded twice. - var cssCacheStatus; // Css cache status - var eventEls; - var isOkToSelect; // Boolean variable indicating if it's ok to make text selections - - this.okToSelect = true; - this.cssCacheStatus = true; // Caching of css files = on(Default) - this.eventEls = new Array(); -} - -DHTMLSuite.common.prototype = { - - // {{{ init() - /** - * This method initializes the DHTMLSuite_common object. - * This class contains a lot of useful methods used by most widgets. - * - * @public - */ - init : function(){ - this.loadedCSSFiles = new Array(); - } - // }}} - , - // {{{ loadCSS() - /** - * This method loads a CSS file(Cascading Style Sheet) dynamically - i.e. an alternative to tag in the document. - * - * @param string cssFile = Name of css file. It will be loaded from the path specified in the DHTMLSuite.common object - * @param Boolean prefixConfigPath = Use config path as prefix. - * @public - */ - loadCSS : function(cssFile,prefixConfigPath){ - if(!prefixConfigPath && prefixConfigPath!==false)prefixConfigPath=true; - if(!this.loadedCSSFiles[cssFile]){ - this.loadedCSSFiles[cssFile] = true; - var lt = document.createElement('LINK'); - if(!this.cssCacheStatus){ - if(cssFile.indexOf('?')>=0)cssFile = cssFile + '&'; else cssFile = cssFile + '?'; - cssFile = cssFile + 'rand='+ Math.random(); // To prevent caching - } - if(prefixConfigPath){ - lt.href = DHTMLSuite.configObj.cssPath + cssFile; - }else{ - lt.href = cssFile; - } - lt.rel = 'stylesheet'; - lt.media = 'screen'; - lt.type = 'text/css'; - document.getElementsByTagName('HEAD')[0].appendChild(lt); - } - } - // }}} - , - // {{{ __setTextSelOk() - /** - * Is it ok to make text selections ? - * - * @param Boolean okToSelect - * @private - */ - __setTextSelOk : function(okToSelect){ - this.okToSelect = okToSelect; - } - // }}} - , - // {{{ __setTextSelOk() - /** - * Returns true if it's ok to make text selections, false otherwise. - * - * @return Boolean okToSelect - * @private - */ - __isTextSelOk : function(){ - return this.okToSelect; - } - // }}} - , - // {{{ setCssCacheStatus() - /** - * Specify if css files should be cached or not. - * - * @param Boolean cssCacheStatus = true = cache on, false = cache off - * - * @public - */ - setCssCacheStatus : function(cssCacheStatus){ - this.cssCacheStatus = cssCacheStatus; - } - // }}} - , - // {{{ getEl() - /** - * Return a reference to an object - * - * @param Object elRef = Id, name or direct reference to element - * @return Object HTMLElement - direct reference to element - * @public - */ - getEl : function(elRef){ - if(typeof elRef=='string'){ - if(document.getElementById(elRef))return document.getElementById(elRef); - if(document.forms[elRef])return document.forms[elRef]; - if(document[elRef])return document[elRef]; - if(window[elRef])return window[elRef]; - } - return elRef; // Return original ref. - - } - // }}} - , - // {{{ isArray() - /** - * Return true if element is an array - * - * @param Object el = Reference to HTML element - * @public - */ - isArray : function(el){ - if(el.constructor.toString().indexOf("Array") != -1)return true; - return false; - } - // }}} - , - // {{{ getStyle() - /** - * Return specific style attribute for an element - * - * @param Object el = Reference to HTML element - * @param String property = Css property - * @public - */ - getStyle : function(el,property){ - el = this.getEl(el); - if (document.defaultView && document.defaultView.getComputedStyle) { - var retVal = null; - var comp = document.defaultView.getComputedStyle(el, ''); - if (comp){ - retVal = comp[property]; - } - return el.style[property] || retVal; - } - if (document.documentElement.currentStyle && DHTMLSuite.clientInfoObj.isMSIE){ - var retVal = null; - if(el.currentStyle)value = el.currentStyle[property]; - return (el.style[property] || retVal); - } - return el.style[property]; - } - // }}} - , - // {{{ getLeftPos() - /** - * This method will return the left coordinate(pixel) of an HTML element - * - * @param Object el = Reference to HTML element - * @public - */ - getLeftPos : function(el){ - /* - if(el.getBoundingClientRect){ // IE - var box = el.getBoundingClientRect(); - return (box.left/1 + Math.max(document.body.scrollLeft,document.documentElement.scrollLeft)); - } - */ - if(document.getBoxObjectFor){ - if(el.tagName!='INPUT' && el.tagName!='SELECT' && el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).x - } - var returnValue = el.offsetLeft; - while((el = el.offsetParent) != null){ - if(el.tagName!='HTML'){ - returnValue += el.offsetLeft; - if(document.all)returnValue+=el.clientLeft; - } - } - return returnValue; - } - // }}} - , - // {{{ getTopPos() - /** - * This method will return the top coordinate(pixel) of an HTML element/tag - * - * @param Object el = Reference to HTML element - * @public - */ - getTopPos : function(el){ - /* - if(el.getBoundingClientRect){ // IE - var box = el.getBoundingClientRect(); - return (box.top/1 + Math.max(document.body.scrollTop,document.documentElement.scrollTop)); - } - */ - if(document.getBoxObjectFor){ - if(el.tagName!='INPUT' && el.tagName!='SELECT' && el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).y - } - - var returnValue = el.offsetTop; - while((el = el.offsetParent) != null){ - if(el.tagName!='HTML'){ - returnValue += (el.offsetTop - el.scrollTop); - if(document.all)returnValue+=el.clientTop; - } - } - return returnValue; - } - // }}} - , - // {{{ getCookie() - /** - * - * These cookie functions are downloaded from - * http://www.mach5.com/support/analyzer/manual/html/General/CookiesJavaScript.htm - * - * This function returns the value of a cookie - * - * @param String name = Name of cookie - * @param Object inputObj = Reference to HTML element - * @public - */ - getCookie : function(name) { - var start = document.cookie.indexOf(name+"="); - var len = start+name.length+1; - if ((!start) && (name != document.cookie.substring(0,name.length))) return null; - if (start == -1) return null; - var end = document.cookie.indexOf(";",len); - if (end == -1) end = document.cookie.length; - return unescape(document.cookie.substring(len,end)); - } - // }}} - , - // {{{ setCookie() - /** - * - * These cookie functions are downloaded from - * http://www.mach5.com/support/analyzer/manual/html/General/CookiesJavaScript.htm - * - * This function creates a cookie. (This method has been slighhtly modified) - * - * @param String name = Name of cookie - * @param String value = Value of cookie - * @param Int expires = Timestamp - days - * @param String path = Path for cookie (Usually left empty) - * @param String domain = Cookie domain - * @param Boolean secure = Secure cookie(SSL) - * - * @public - */ - setCookie : function(name,value,expires,path,domain,secure) { - expires = expires * 60*60*24*1000; - var today = new Date(); - var expires_date = new Date( today.getTime() + (expires) ); - var cookieString = name + "=" +escape(value) + - ( (expires) ? ";expires=" + expires_date.toGMTString() : "") + - ( (path) ? ";path=" + path : "") + - ( (domain) ? ";domain=" + domain : "") + - ( (secure) ? ";secure" : ""); - document.cookie = cookieString; - } - // }}} - , - // {{{ deleteCookie() - /** - * - * This function deletes a cookie. (This method has been slighhtly modified) - * - * @param String name = Name of cookie - * @param String path = Path for cookie (Usually left empty) - * @param String domain = Cookie domain - * - * @public - */ - deleteCookie : function( name, path, domain ) - { - if ( this.getCookie( name ) ) document.cookie = name + "=" + - ( ( path ) ? ";path=" + path : "") + - ( ( domain ) ? ";domain=" + domain : "" ) + - ";expires=Thu, 01-Jan-1970 00:00:01 GMT"; - } - // }}} - , - // {{{ cancelEvent() - /** - * - * This function only returns false. It is used to cancel selections and drag - * - * - * @public - */ - - cancelEvent : function(){ - return false; - } - // }}} - , - // {{{ addEvent() - /** - * - * This function adds an event listener to an element on the page. - * - * @param Object whichObject = Reference to HTML element(Which object to assigne the event) - * @param String eventType = Which type of event, example "mousemove" or "mouseup" (NOT "onmousemove") - * @param functionName = Name of function to execute. - * - * @public - */ - addEvent : function( obj, type, fn,suffix ) { - if(!suffix)suffix = ''; - if ( obj.attachEvent ) { - if ( typeof DHTMLSuite_funcs[type+fn+suffix] != 'function') { - DHTMLSuite_funcs[type+fn+suffix] = function() { - fn.apply(window.event.srcElement); - }; - obj.attachEvent('on'+type, DHTMLSuite_funcs[type+fn+suffix] ); - } - obj = null; - } else { - obj.addEventListener( type, fn, false ); - } - this.__addEventEl(obj); - } - - // }}} - , - // {{{ removeEvent() - /** - * - * This function removes an event listener from an element on the page. - * - * @param Object whichObject = Reference to HTML element(Which object to assigne the event) - * @param String eventType = Which type of event, example "mousemove" or "mouseup" - * @param functionName = Name of function to execute. - * - * @public - */ - removeEvent : function(obj,type,fn,suffix){ - if ( obj.detachEvent ) { - obj.detachEvent( 'on'+type, DHTMLSuite_funcs[type+fn+suffix] ); - DHTMLSuite_funcs[type+fn+suffix] = null; - obj = null; - } else { - obj.removeEventListener( type, fn, false ); - } - } - // }}} - , - // {{{ __clearMemoryGarbage() - /** - * - * This function is used for Internet Explorer in order to clear memory when the page unloads. - * - * - * @private - */ - __clearMemoryGarbage : function(){ - /* Example of event which causes memory leakage in IE - DHTMLSuite.commonObj.addEvent(expandRef,"click",function(){ window.refToMyMenuBar[index].__changeMenuBarState(this); }) - We got a circular reference. - */ - if(!DHTMLSuite.clientInfoObj.isMSIE)return; - - for(var no=0;no'; - img.outerHTML = html; - - } - , - // {{{ __evaluateJs() - /** - * Evaluate Javascript in the inserted content - * - * @private - */ - __evaluateJs : function(obj){ - obj = this.getEl(obj); - var scriptTags = obj.getElementsByTagName('SCRIPT'); - var string = ''; - var jsCode = ''; - for(var no=0;no tag. - * - * @private - */ - __installScript : function ( script ){ - try{ - if (!script) - return; - if (window.execScript){ - window.execScript(script) - }else if(window.jQuery && jQuery.browser.safari){ // safari detection in jQuery - window.setTimeout(script,0); - }else{ - window.setTimeout( script, 0 ); - } - }catch(e){ - - } - } - // }}} - , - // {{{ __evaluateCss() - /** - * Evaluates css - * - * @private - */ - __evaluateCss : function(obj){ - obj = this.getEl(obj); - var cssTags = obj.getElementsByTagName('STYLE'); - var head = document.getElementsByTagName('HEAD')[0]; - for(var no=0;no=0)?true:false; - this.isFirefox = (this.browser.toLowerCase().indexOf('firefox')>=0)?true:false; - this.isMSIE = (this.browser.toLowerCase().indexOf('msie')>=0)?true:false; - this.isOldMSIE = (this.browser.toLowerCase().match(/msie\s[0-6]/gi))?true:false; - this.isSafari = (this.browser.toLowerCase().indexOf('safari')>=0)?true:false; - this.navigatorVersion = navigator.appVersion.replace(/.*?MSIE\s(\d\.\d).*/g,'$1')/1; - this.isOldMSIE = (this.isMSIE&&this.navigatorVersion<7)?true:false; - } - // }}} - , - // {{{ getBrowserWidth() - /** - * - * - * This method returns the width of the browser window(i.e. inner width) - * - * - * @public - */ - getBrowserWidth : function(){ - if(self.innerWidth)return self.innerWidth; - return document.documentElement.offsetWidth; - } - // }}} - , - // {{{ getBrowserHeight() - /** - * - * - * This method returns the height of the browser window(i.e. inner height) - * - * - * @public - */ - getBrowserHeight : function(){ - if(self.innerHeight)return self.innerHeight; - return document.documentElement.offsetHeight; - } -} - -/************************************************************************************************************ -* DOM query class -* -* Created: August, 31th, 2006 -* -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class Purpose of class: Gives you a set of methods for querying elements on a webpage. When an object -* of this class has been created, the method will also be available via the document object. -* Example: var elements = document.getElementsByClassName('myClass'); -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.domQuery = function(){ - // Make methods of this class a member of the document object. - document.getElementsByClassName = this.getElementsByClassName; - document.getElementsByAttribute = this.getElementsByAttribute; -} - -DHTMLSuite.domQuery.prototype = { -} - -/*[FILE_START:dhtmlSuite-tableWidget.js] */ -/************************************************************************************************************ -* Table widget page handler class -* -* Created: December, 15th, 2006 -* Purpose of class: Displays paginating below a server sorted table -* -* CSS used: -* -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class Purpose of class: Make HTML tables sortable

-*/ -DHTMLSuite.tableWidgetPageHandler=function(){ - var tableRef; - // Reference to object of class DHTMLSuite.tableWidget - var targetRef; - // Where to insert the pagination. - - var txtPrevious; - // Label-"Previous" - var txtNext; - // Label-"Next" - var txtFirst; - // Label-"First" - var txtLast; - // Label-"last" - - var txtResultPrefix; - // Prefix:result-default="Result: " - var txtResultTo; - // Text label Result: 1 "to" 10 of 51-default value="to" - var txtResultOf; - // Text label Result: 1 to 10 "of" 51-default value="of" - - var totalNumberOfRows; - // Total number of rows in dataset - var rowsPerPage; - // Number of rows per page. - - var layoutCSS; - // Name of CSS file for the table widget. - var activePageNumber; - // Active page number - var mainDivEl; - // Reference to main div for the page handler - var resultDivElement; - // Reference to div element which is parent for the result - var pageListDivEl; - // Reference to div element which is parent to pages [1],[2],[3]...[Next] - - var objectIndex; - // Index of this widget in the arrayDSObjects array - - var linkPagePrefix; - // Text in front of each page link - var linkPageSuffix; - // Text behind each page link - - var maximumNumberOfPageLinks; - // Maximum number of page links. - var callbackOnAfterNavigate; - // Callback function-executed when someone navigates to a different page - this.txtPrevious='Previous'; - // Default label - this.txtNext='Next'; - // Default label - this.txtResultPrefix='Result: '; - // Default label - this.txtResultTo='to'; - // Default label - this.txtResultOf='of'; - // Default label - this.txtFirst='First'; - this.txtLast='Last'; - - this.tableRef=false; - this.targetRef=false; - this.totalNumberOfRows=false; - this.activePageNumber=0; - this.layoutCSS='table-widget-page-handler.css'; - - this.linkPagePrefix=''; - this.linkPageSuffix=''; - this.maximumNumberOfPageLinks=false; - this.callbackOnAfterNavigate=false; - - this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this; - -} - -DHTMLSuite.tableWidgetPageHandler.prototype={ - - // {{{ setTableRef() - /** - * Connect to a tableWidget object. - * - * @param Object tableRef=An object of class DHTMLSuite.tableWidget. It makes it possible for the tableWidget and this object to communicate. - * - *@public - */ - setTableRef:function(tableRef){ - this.tableRef=tableRef; - this.tableRef.setPageHandler(this); - } - - // }}} - , - - // {{{ setTargetId() - /** - * Where do you want to insert the navigation links for the table - * - * @param String idOfHTMLElement=Id of HTML Element on your page. - * - *@public - */ - setTargetId:function(idOfHTMLElement){ - if(!document.getElementById(idOfHTMLElement)){ - alert('ERROR IN tableWidgetPageHandler.setTargetId:\nElement with id '+idOfHTMLElement+' does not exists'); - return; - } - this.targetRef=document.getElementById(idOfHTMLElement); - } - - // }}} - , - - // {{{ setTxtPrevious() - /** - * Set text label (previous page link) - * - * @param String newText=Text previous page link - * - *@public - */ - setTxtPrevious:function(newText){ - this.txtPrevious=newText; - } - - // }}} - , - - // {{{ setLinkPagePrefix() - /** - * Set text/characters in front of each page link, example "[" to get page number in brackets - * - * @param String linkPagePrefix=Character(s)in front of page links - * - *@public - */ - setLinkPagePrefix:function(linkPagePrefix){ - this.linkPagePrefix=linkPagePrefix; - } - - // }}} - , - - // {{{ setLinkPageSuffix() - /** - * Set text/characters in front of each page link, example "[" to get page number in brackets - * - * @param String linkPageSuffix=Character(s)in front of page links - * - *@public - */ - setLinkPageSuffix:function(linkPageSuffix){ - this.linkPageSuffix=linkPageSuffix; - } - - // }}} - , - - // {{{ setTxtNext() - /** - * Set text label (next page link) - * - * @param String newText=Text next page link - * - *@public - */ - setTxtNext:function(newText){ - this.txtNext=newText; - } - - // }}} - , - - // {{{ setTxtResultOf() - /** - * Set text label ("of"-result) - * - * @param String txtResultOf=Result of search, the "of" label ( Result: 1 to 10 "of" 51 ) - * - *@public - */ - setTxtResultOf:function(txtResultOf){ - this.txtResultOf=txtResultOf; - } - - // }}} - , - - // {{{ setTxtResultTo() - /** - * Set text label ("to"-result) - * - * @param String txtResultTo=Result of search, the "to" label ( Result: 1 "to" 10 of 51 ) - * - *@public - */ - setTxtResultTo:function(txtResultTo){ - this.txtResultTo=txtResultTo; - } - - // }}} - , - - // {{{ setTxtResultPrefix() - /** - * Set text label (prefix-result) - * - * @param String txtResultPrefix=Text next page link - * - *@public - */ - setTxtResultPrefix:function(txtResultPrefix){ - this.txtResultPrefix=txtResultPrefix; - } - - // }}} - , - - // {{{ setTxtFirstPage() - /** - * Set text label ("Last" page) - * - * @param String txtFirst=Label of link to "First" page ( default="First" ).This option is only used when you are limiting the number of pages shown. - * - *@public - */ - setTxtFirstPage:function(txtFirst){ - this.txtFirst=txtFirst; - } - - // }}} - , - - // {{{ setTxtLastPage() - /** - * Set text label ("First" page) - * - * @param String txtLast=Label of link to "Last" page ( default="Last" ).This option is only used when you are limiting the number of pages shown. - * - *@public - */ - setTxtLastPage:function(txtLast){ - this.txtLast=txtLast; - } - - // }}} - , - - // {{{ setTotalNumberOfRows() - /** - * Specify total number of rows in the entire dataset - * - * @param Integer totalNumberOfRows=Total number of rows in the entire dataset. - * - *@public - */ - setTotalNumberOfRows:function(totalNumberOfRows){ - this.totalNumberOfRows=totalNumberOfRows; - } - - // }}} - , - - // {{{ setCallbackOnAfterNavigate() - /** - *Specify call back function to execute after page navigatoin - * - *@param String callbackOnAfterNavigate-name of javascript function. - * - *@public - */ - setCallbackOnAfterNavigate:function(callbackOnAfterNavigate){ - this.callbackOnAfterNavigate=callbackOnAfterNavigate; - } - - // }}} - , - - // {{{ setLayoutCss() - /** - *set new CSS file - * - *@param String cssFileName-name of new css file(example: drag-drop.css). Has to be set before init is called. - * - *@public - */ - setLayoutCss:function(layoutCSS){ - this.layoutCSS=layoutCSS; - } - - // }}} - , - - // {{{ setMaximumNumberOfPageLinks() - /** - *Set maximum number of page links displayed below the table, i.e. if you have 50 pages, you can limit number of page links to 10 by sending 10 to this method. - * - *@param Integer maximumNumberOfPageLinks-(0 or false means=no limitation) - * - *@public - */ - setMaximumNumberOfPageLinks:function(maximumNumberOfPageLinks){ - this.maximumNumberOfPageLinks=maximumNumberOfPageLinks; - } - - // }}} - , - - // {{{ init() - /** - *Initializes the script widget. Set methods should be called before your call this method. - * - * - *@public - */ - init:function(){ - this.rowsPerPage=this.tableRef.getServersideSortNumberOfRows(); - DHTMLSuite.commonObj.loadCSS(this.layoutCSS); - this.__createMainDivEls(); - this.setHTMLOfResultList(); - this.__createPageLinks(); - this.goToPage(1); - } - - // }}} - , - - // {{{ __createMainDivEls() - /** - *Create main div elements for the page handler - * - * - *@private - */ - __createMainDivEls:function(){ - if(!this.targetRef){ - alert('Error creating table widget page handler. Remember to specify targetRef'); - return; - } - this.mainDivEl=document.createElement('DIV'); - this.mainDivEl.className='DHTMLSuite_tableWidgetPageHandler_mainDiv'; - this.targetRef.appendChild(this.mainDivEl); - - this.resultDivElement=document.createElement('DIV'); - this.resultDivElement.className='DHTMLSuite_tableWidgetPageHandler_result'; - this.mainDivEl.appendChild(this.resultDivElement); - - this.pageListDivEl=document.createElement('DIV'); - this.pageListDivEl.className='DHTMLSuite_tableWidgetPageHandler_pageList'; - this.mainDivEl.appendChild(this.pageListDivEl); - } - - , - - // {{{ setHTMLOfResultList() - /** - * - * Create result list div - * - * - * - *@public - */ - setHTMLOfResultList:function(){ - this.resultDivElement.innerHTML=''; - var html=this.txtResultPrefix+(((this.activePageNumber-1)* this.rowsPerPage)+1)+' '+this.txtResultTo+' '+Math.min(this.totalNumberOfRows,(this.activePageNumber*this.rowsPerPage))+' '+this.txtResultOf+' '+this.totalNumberOfRows; - this.resultDivElement.innerHTML=html; - } - - // }}} - , - - // {{{ __createPageLinks() - /** - * - * Create page links - * - *@private - */ - __createPageLinks:function(){ - var ind=this.objectIndex; - this.pageListDivEl.innerHTML=''; - // Clearing the div element if it allready got content. - var numberOfPages=Math.ceil(this.totalNumberOfRows/this.rowsPerPage); - - /* link to first page */ - if(this.maximumNumberOfPageLinks&&this.maximumNumberOfPageLinks=0){ - var pageNo=src.id.replace(/[^0-9]/gi,'')/1; - this.activePageNumber=pageNo; - - } - if(src.id=='next'){ - // next link clicked - this.activePageNumber++; - if(this.activePageNumber>numberOfPages)this.activePageNumber=numberOfPages; - } - if(src.id=='previous'){ - this.activePageNumber--; - if(this.activePageNumber<1)this.activePageNumber=1; - } - - if(this.activePageNumber!=initActivePageNumber){ - this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage); - this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate); - this.setHTMLOfResultList(); - this.__createPageLinks(); - } - return false; - - } - - // }}} - , - - // {{{ __resetActivePageNumber() - /** - * - * Reset active page number-called from the tableWidget - * - * - *@private - */ - __resetActivePageNumber:function(){ - this.activePageNumber=1; - this.setHTMLOfResultList(); - this.__createPageLinks(); - } - - // }}} - , - - // {{{ goToPage() - /** - * - * Go to a page - * @param Integer pageNumber - * - * - *@public - */ - goToPage:function(pageNo){ - var initActivePageNumber=this.activePageNumber; - this.activePageNumber=pageNo; - if(this.activePageNumber!=initActivePageNumber){ - this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage); - this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate); - this.setHTMLOfResultList(); - this.__createPageLinks(); - } - } -} - -/************************************************************************************************************ -* Table widget class -* -* Created: August, 18th, 2006 -* Purpose of class: Make HTML tables sortable -* Apply application look to the table -* Create one object for each HTML table. -* -* CSS used: table-widget.css -* images used: arrow_up.gif -* arrow_down.gif -* -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class Purpose of class: Make HTML tables sortable

-* Apply application look to the table
-* Create one object for each HTML table.
-*
-* Remember to have both <THEAD> and <TBODY> in your table. -*
-* <DIV>
-* <table>
-* <thead>
-* <tr>
-* <td>Header cell</td>
-* <td>Header cell</td>
-* </tr>
-* </thead>
-* <tbody>
-* <tr>
-* <td>Table data</td>
-* <td>Table data</td>
-* </tr>
-* <tr>
-* <td>Table data</td>
-* <td>Table data</td>
-* </tr>
-* </tbody>
-* </table>
-* </div>
-*

-* Also remember: If you put a table inside a non-displayed element, example an inactive tab(the tabView script), remember to create -* and initialize the table objects before you create the tab objects. In some browsers, that's nescessary in order for the table to -* display properly.
-* (demo 1) -* -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.tableWidget=function(){ - var tableWidget_okToSort; - // Variable indicating if it's ok to sort. This variable is "false" when sorting is in progress - var activeColumn; - // Reference to active column, i.e. column currently beeing sorted - var idOfTable; - // Id of table, i.e. the tag - var tableObj; - // Reference to
tag. - var widthOfTable; - // Width of table (Used in the CSS) - var heightOfTable; - // Height of table (Used in the CSS) - var columnSortArray; - // Array of how table columns should be sorted - var layoutCSS; - // Name of CSS file for the table widget. - var noCssLayout; - // true or false, indicating if the table should have layout or not, if not, it would be a plain sortable table. - var serversideSort; - // true or false, true if the widget is sorted on the server. - var serversideSortAscending; - var tableCurrentlySortedBy; - var serversideSortFileName; - // Name of file on server to send request to when table data should be sorted - var serversideSortNumberOfRows; - // Number of rows to receive from the server - var serversideSortCurrentStartIndex; - // Index of first row in the dataset, i.e. if you move to next page, this value will be incremented - var serversideSortExtraSearchCriterias; - // Extra param to send to the server, example: &firstname=Alf&lastname=Kalleland - var pageHandler; - // Object of class DHTMLSuite.tableWidgetPageHandler - var rowClickCallBackFunction; - // Row click call back function. - var objectIndex; - // Index of this object in the DHTMLSuite.variableStorage.arrayDSObjects array - - this.serversideSort=false; - // Default value for serversideSort(items are sorted in the client) - this.serversideSortAscending=true; - // Current sort ( ascending or descending) - this.tableCurrentlySortedBy=false; - this.serversideSortFileName=false; - this.serversideSortCurrentStartIndex=0; - this.serversideSortExtraSearchCriterias=''; - this.rowClickCallBackFunction=false; - this.setRowDblClickCallBackFunction=false; - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); - // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - - this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this; -} - -DHTMLSuite.tableWidget.prototype={ - /** - * Public method used to initialize the table widget script. First use the set methods to configure the script, then - * call the init method. - **/ - - // {{{ init() - /** - * - * Initializes the table widget object - * - * - *@public - */ - init:function(){ - this.tableWidget_okToSort=true; - this.activeColumn=false; - if(!this.layoutCSS)this.layoutCSS='table-widget.css'; - DHTMLSuite.commonObj.loadCSS(this.layoutCSS); - this.__initTableWidget(); - } - - // }}} - , - - // {{{ setLayoutCss() - /** - * - * This function updates name of CSS file. This method should be called before init(). - * - *@param String newCssFile=(File name of CSS file, not path) - * - *@public - */ - setLayoutCss:function(newCssFile){ - this.layoutCSS=newCssFile; - } - - // }}} - , - - // - // {{{ setRowClickCallBackFunction() - /** - * - * This method specifies call back function to be called when a row is clicked. A reference to that row is sent as argument to this function - * - *@param String rowClickCallBackFunction=(Row click-call back function) - * - *@public - */ - setRowClickCallBack:function(rowClickCallBackFunction){ - this.rowClickCallBackFunction=rowClickCallBackFunction; - } - - // }}} - , - - // - // {{{ setRowDblClickCallBackFunction() - /** - * - * This method specifies call back function to be called when a row is double clicked. A reference to that row is sent as argument to this function - * - *@param String setRowDblClickCallBackFunction=(Row click-call back function) - * - *@public - */ - setRowDblClickCallBack:function(setRowDblClickCallBackFunction){ - this.setRowDblClickCallBackFunction=setRowDblClickCallBackFunction; - } - - // }}} - , - - // {{{ setServerSideSort() - /** - * - * This method is used to specify if you want to your tables to be sorted on the server or not. - * - *@param Boolean serversideSort=Sort items on the server? (true=yes, false=no). - * - *@public - */ - setServerSideSort:function(serversideSort){ - this.serversideSort=serversideSort; - } - - // }}} - , - - // {{{ setServersideSearchCriterias() - /** - * - * This method is used to add extra params to the search url sent to the server. - * - *@param String serversideSortExtraSearchCriterias=String added to the url, example: "&firstname=John&lastname=Doe". This can be used in the sql query on the server. - * - *@public - */ - setServersideSearchCriterias:function(serversideSortExtraSearchCriterias){ - this.serversideSortExtraSearchCriterias=serversideSortExtraSearchCriterias; - } - - // }}} - , - - // {{{ getServersideSortNumberOfRows() - /** - * - * Return numer of rows per page. - * - *@return Integer serversideSort=Number of rows - * - *@public - */ - getServersideSortNumberOfRows:function(serversideSort){ - return this.serversideSortNumberOfRows; - } - - // }}} - , - - // {{{ setServersideSortNumberOfRows() - /** - * - * Specify how many records to receive from the server ( server side sort ) - * - *@param Integer serversideSortNumberOfRows=Number of rows - * - *@public - */ - setServersideSortNumberOfRows:function(serversideSortNumberOfRows){ - this.serversideSortNumberOfRows=serversideSortNumberOfRows; - } - - // }}} - , - - // {{{ setServersideSortFileName() - /** - * - * This method is used to specify which file to send the ajax request to when data should be sorted. (i.e. sort items on server instead of client). - * - *@param String serversideSortFileName=Path to file on server. This file will receive the request, parse it and send back new table data. - * - *@public - */ - setServersideSortFileName:function(serversideSortFileName){ - this.serversideSortFileName=serversideSortFileName; - } - - // }}} - , - /* Start public methods */ - - // {{{ setNoCssLayout() - /** - * - * No CSS layout - * - * - *@public - */ - setNoCssLayout:function(){ - this.noCssLayout=true; - } - - // }}} - , - - // {{{ sortTableByColumn() - /** - * - * This method sorts a table by a column - * You can call this method after the call to init if you want to sort the table by a column when the table is beeing displayed. - * - *@param Int columnIndex=Column to sort by (0=first column) - *@param String howToSort How to sort the table ("ascending" or "descending" - * - *@public - */ - sortTableByColumn:function(columnIndex,howToSort){ - if(!howToSort)howToSort='ascending'; - var tableObj=document.getElementById(this.idOfTable); - var firstRow=tableObj.rows[0]; - var tds=firstRow.cells; - if(tds[columnIndex]&&this.columnSortArray[columnIndex]){ - this.__sortTable(tds[columnIndex],howToSort); - } - } - - // }}} - , - - // {{{ setTableId() - /** - * - * Set id of table, i.e. the id of the
tag you want to apply the table widget to - * - *@param String idOfTable=Id of table - * - *@public - */ - setTableId:function(idOfTable){ - this.idOfTable=idOfTable; - try{ - this.tableObj=document.getElementById(idOfTable); - }catch(e){ - - } - } - - // }}} - , - - // {{{ setTableWidth() - /** - * - * Set width of table - * - *@param Mixed width=(string if percentage width, integer if numeric/pixel width) - * - *@public - */ - setTableWidth:function(width){ - this.widthOfTable=width; - } - - // }}} - , - - // {{{ setTableHeight() - /** - * - * Set height of table - * - *@param Mixed height=(string if percentage height, integer if numeric/pixel height) - * - *@public - */ - setTableHeight:function(height){ - this.heightOfTable=height; - } - - // }}} - , - - // {{{ setColumnSort() - /** - * - * How to sort the table - * - *@param Array columnSortArray=How to sort the columns in the table(An array of the items 'N','S' or false) - * - *@public - */ - setColumnSort:function(columnSortArray){ - this.columnSortArray=columnSortArray; - } - - // }}} - , - - // {{{ addNewRow() - /** - * Adds a new row to the table dynamically - * - *@param Array cellContent=Array of strings-cell content - * - *@public - */ - addNewRow:function(cellContent){ - var tObj=document.getElementById(this.idOfTable); - var tb=tObj.getElementsByTagName('TBODY')[0]; - - var row=tb.insertRow(-1); - for(var no=0;no - var tbody=tableObj.getElementsByTagName('TBODY')[0]; - // Reference to the - var thead=tableObj.getElementsByTagName('THEAD')[0]; - // Reference to the - - var bodyRows=tbody.rows; - // Reference to all the inside the tag - var headerRows=thead.rows; - // Reference to all inside - - cellIndexSubtract=1; - // Firefox have a small cell at the right of each row which means that the new column should not be the last one, but second to last. - if(DHTMLSuite.clientInfoObj.isMSIE)cellIndexSubtract=0; - // Browser does not have this cell at the right - - // Add new header cell - var headerCell=headerRows[0].insertCell(headerRows[0].cells.length-cellIndexSubtract); - if(!this.noCssLayout)headerCell.className='DHTMLSuite_tableWidget_headerCell'; - headerCell.onselectstart=function(){ return false; }; - DHTMLSuite.commonObj.__addEventEl(headerCell); - headerCell.innerHTML=headerText; - if(sortMethod){ - this.__parseHeaderCell(headerCell); - }else{ - headerCell.style.cursor='default'; - } - - // Setting width of header cells. The last cell shouldn't have any right border - headerRows[0].cells[headerRows[0].cells.length-1].style.borderRightWidth='0px'; - headerRows[0].cells[headerRows[0].cells.length-2].style.borderRightWidth='1px'; - - // Add rows to the table - for(var no=0;no - * - *@private - */ - __parseHeaderCell:function(cellRef){ - if(!this.noCssLayout){ - cellRef.onmouseover=this.__highlightTableHeader; - cellRef.onmouseout= this.__removeHighlightEffectFromTableHeader; - cellRef.onmousedown=this.__mousedownOnTableHeader; - cellRef.onmouseup=this.__highlightTableHeader; - }else{ - cellRef.style.cursor='pointer'; - // No CSS layout -> just set cursor to pointer/hand. - } - - var refToThis=this; - // It doesn't work with "this" on the line below, so we create a variable refering to "this". - cellRef.onclick=function(){ refToThis.__sortTable(this); }; - DHTMLSuite.commonObj.__addEventEl(cellRef); - - var img=document.createElement('IMG'); - img.src=DHTMLSuite.configObj.imagePath+'table-widget/arrow_up.gif'; - cellRef.appendChild(img); - img.style.visibility='hidden'; - } - - // }}} - , - - // {{{ __parseDataRows() - /** - * Parses rows in a table, i.e. add events and align cells. - * - *@param Object parentObj=Reference to
- * - *@private - */ - __parseDataRows:function(parentObj){ - var ind=this.objectIndex; - - // Loop through rows and assign mouseover and mouse out events+right align numeric cells. - for(var no=1;no=0){ - obj.style.width='100%'; - obj.parentNode.style.width=this.widthOfTable; - }else{ - obj.style.width=this.widthOfTable+'px'; - obj.parentNode.style.width=this.widthOfTable+'px'; - } - if(this.heightOfTable.indexOf('%')>=0){ - obj.parentNode.style.height=this.heightOfTable; - }else{ - obj.parentNode.style.height=this.heightOfTable+'px'; - } - } - if(!DHTMLSuite.clientInfoObj.isMSIE){ - this.__addEndCol(obj); - }else{ - obj.style.cssText='width:expression(this.parentNode.clientWidth)'; - } - - obj.cellSpacing=0; - obj.cellPadding=0; - if(!this.noCssLayout)obj.className='DHTMLSuite_tableWidget'; - var tHead=obj.getElementsByTagName('THEAD')[0]; - var cells=tHead.getElementsByTagName('TD'); - - var tBody=obj.getElementsByTagName('TBODY')[0]; - tBody.className='DHTMLSuite_scrollingContent'; - - for(var no=0;no=0){ - obj.parentNode.style.overflow='auto'; - } - } - } - this.__parseDataRows(obj); - var ind=this.objectIndex; - } - - // }}} - , - - // {{{ __addEndCol() - /** - * Adds a small empty cell at the right of the header row. This is done in order to make the table look pretty when the scrollbar appears. - * - *@param Object obj=Reference to
- * - *@private - */ - __addEndCol:function(obj){ - var rows=obj.getElementsByTagName('TR'); - for(var no=0;no'; - cell.style.width='13px'; - cell.width='13'; - cell.style.overflow='hidden'; - } - - } - - // }}} - , - - // {{{ __highlightTableHeader() - /** - * Mouse over event: Highlights header cell on mouse over, i.e. applies an orange line at the top. - * - * - *@private - */ - __highlightTableHeader:function(){ - - // Here, "this" is a reference to the HTML tag triggering this event and not the table widget object - this.className='DHTMLSuite_tableWigdet_headerCellOver'; - if(document.all){ - // I.E fix for "jumping" headings - var divObj=this.parentNode.parentNode.parentNode.parentNode; - this.parentNode.style.top=divObj.scrollTop+'px'; - } - } - - // }}} - , - - // {{{ __removeHighlightEffectFromTableHeader() - /** - * Mouse out event: Remove the orange line at the top of header cells when the mouse moves away from the cell. - * - * - *@private - */ - __removeHighlightEffectFromTableHeader:function(){ - this.className='DHTMLSuite_tableWidget_headerCell'; - } - - // }}} - , - - // {{{ __mousedownOnTableHeader() - /** - * Mouse down event header cells. It changes the color of the header from light gray to dark gray. - * - *@private - */ - __mousedownOnTableHeader:function(){ - this.className='DHTMLSuite_tableWigdet_headerCellDown'; - if(document.all){ - // I.E fix for "jumping" headings - var divObj=this.parentNode.parentNode.parentNode.parentNode; - this.parentNode.style.top=divObj.scrollTop+'px'; - } - } - - // }}} - , - - // {{{ __sortNumeric() - /** - * Sort the table numerically - * ps! If you know that your tables always contains valid numbers(i.e. digits or decimal numbers like 7 and 7.5), - * then you can remove everything except return a/1-b/1; from this function. By removing these lines, the sort - * process be faster. - * - *@param String a=first number to compare - *@param String b=second number to compare - * - *@private - */ - __sortNumeric:function(a,b){ - - // changing commas(,)to periods(.) - a=a.replace(/,/,'.'); - b=b.replace(/,/,'.'); - - // Remove non digit characters-example changing "DHTML12.5" to "12.5" - a=a.replace(/[^\d\.\/]/g,''); - b=b.replace(/[^\d\.\/]/g,''); - - // Dealing with fractions(example: changing 4/5 to 0.8) - if(a.indexOf('/')>=0)a=eval(a); - if(b.indexOf('/')>=0)b=eval(b); - return a/1-b/1; - } - - // }}} - , - - // {{{ __sortString() - /** - * Sort the table letterically - * - *@param String a=first number to compare - *@param String b=second number to compare - * - *@private - */ - __sortString:function(a, b){ - if ( a.toUpperCase()< b.toUpperCase())return -1; - if ( a.toUpperCase()> b.toUpperCase())return 1; - return 0; - } - - // }}} - , - - // {{{ __parseDataContentFromServer() - /** - *This method parses data content from server and calls the __fillDataRow method with parsed data as argument. - * - * - *@private - */ - __parseDataContentFromServer:function(ajaxIndex){ - var content=DHTMLSuite.variableStorage.ajaxObjects[ajaxIndex].response; - if(content.indexOf('|||')==-1&&content.indexOf('###')==-1){ - alert('Error in data from server\n'+content); - return; - } - this.__clearDataRows(); - // Clear existing data - var rows=content.split('|||'); - // Create an array of each row - for(var no=0;no1)this.__fillDataRow(items); - } - this.__parseDataRows(this.tableObj); - } - - // }}} - , - - // {{{ __clearDataRows() - /** - *This method clear all data from the table(except header cells). - * - * - *@private - */ - __clearDataRows:function(){ - if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable); - while(this.tableObj.rows.length>1){ - DHTMLSuite.discardElement(this.tableObj.rows[this.tableObj.rows.length-1]); - } - } - - // }} - , - - // {{{ __fillDataRow() - /** - *Adds a new row of data to the table. - * - *@param Array data=Array of data - * - *@private - */ - __fillDataRow:function(data){ - if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable); - var tbody=this.tableObj.getElementsByTagName('TBODY')[0]; - var row=tbody.insertRow(-1); - for(var no=0;no 0 ) - sembol = '&'; - // batur :: end - var url=this.serversideSortFileName + sembol + 'sortBy='+this.tableCurrentlySortedBy+'&numberOfRows='+this.serversideSortNumberOfRows+'&sortAscending='+this.serversideSortAscending+'&startIndex='+this.serversideSortCurrentStartIndex+this.serversideSortExtraSearchCriterias; - var index=DHTMLSuite.variableStorage.ajaxObjects.length; - try{ - DHTMLSuite.variableStorage.ajaxObjects[index]=new sack(); - }catch(e){ - // Unable to create ajax object-send alert message and return from sort method. - alert('Unable to create ajax object. Please make sure that the sack js file is included on your page(js/ajax.js)'); - return; - } - DHTMLSuite.variableStorage.ajaxObjects[index].requestFile=url; - // Specifying which file to get - DHTMLSuite.variableStorage.ajaxObjects[index].onCompletion=function(){ DHTMLSuite.variableStorage.arrayDSObjects[objIndex].__parseDataContentFromServer(index);eval(callbackFunction)}; - // Specify function that will be executed after file has been found - DHTMLSuite.variableStorage.ajaxObjects[index].runAJAX(); - // Execute AJAX function - } - - // }}} - , - - // {{{ __sortTable() - /** - *Sort table-This method is called when someone clicks on the header of one of the sortable columns - * - *@param Object obj=reference to header cell triggering the sortTable method - * - *@private - */ - __sortTable:function(obj,howToSort){ - - // "this" is a reference to the table widget obj - - // "obj" is a reference to the header cell triggering the sortTable method. - - // Server side sort ? - if(this.serversideSort){ - if(!this.serversideSortFileName){ - // Server side file name defined. - alert('No server side file defined. Use the setServersideSortFileName to specify where to send the ajax request'); - return; - } - var sortBy=obj.getAttribute('sortBy'); - if(!sortBy)sortBy=obj.sortBy; - if(!sortBy){ - alert('Sort is not defined. Remember to set a sortBy attribute on the header
tags'); - return; - } - if(sortBy==this.tableCurrentlySortedBy)this.serversideSortAscending=!this.serversideSortAscending;else this.serversideSortAscending=true; - if(howToSort)this.serversideSortAscending=(howToSort=='ascending'?true:false); - this.tableCurrentlySortedBy=sortBy; - this.serversideSortCurrentStartIndex =0; - this.__getItemsFromServer(); - - if(this.pageHandler)this.pageHandler.__resetActivePageNumber(); - this.__updateSortArrow(obj,this.serversideSortAscending?'ascending':'descending'); - - return; - } - - if(!this.tableWidget_okToSort)return; - this.tableWidget_okToSort=false; - /* Getting index of current column */ - var indexThis=0; - var tmpObj=obj; - while(tmpObj.previousSibling){ - tmpObj=tmpObj.previousSibling; - if(tmpObj.tagName=='TD')indexThis++; - } - if(obj.getAttribute('direction')||obj.direction){ - // Determine if we should sort ascending or descending - direction=obj.getAttribute('direction'); - if(navigator.userAgent.indexOf('Opera')>=0)direction=obj.direction; - if(direction=='ascending'||howToSort=='descending'){ - direction='descending'; - obj.setAttribute('direction','descending'); - obj.direction='descending'; - }else{ - direction='ascending'; - obj.setAttribute('direction','ascending'); - obj.direction='ascending'; - } - }else{ - // First call to the sort method - var curDir='ascending'; - // How to sort the table - if(howToSort)curDir=howToSort; - // Initial sort method sent as argument to this method, call it by this method. - direction=curDir; - obj.setAttribute('direction',curDir); - obj.direction=curDir; - } - - this.__updateSortArrow(obj,direction); - var tableObj=obj.parentNode.parentNode.parentNode; - var tBody=tableObj.getElementsByTagName('TBODY')[0]; - var widgetIndex=tableObj.id.replace(/[^\d]/g,''); - var sortMethod=this.columnSortArray[indexThis]; - // N=numeric, S=String - var cellArray=new Array(); - var cellObjArray=new Array(); - for(var no=1;no=0;no--){ - for(var no2=0;no2 -* The constructor takes an associative array as only argument. Possible keys in this array:
-* cloneNode - Clone the node, i.e. make the clone dragable
-* allowMoveX - Allow drag along the x-axis
-* allowMoveY - Allow drag along the y-axis
-* minX - Minimum x coordinate on screen
-* minY - Minimum y coordinate on screen
-* maxX - Maximum x coordinate on screen
-* maxY - Maximum y coordinate on screen
-* callbackOnBeforeDrag - Name of function to execute before drag starts - The event object will be sent to this function.
-* callbackOnAfterDrag - Name of function to execute after drag - The event object will be sent to this function.
-* callbackOnDuringDrag - Name of function to execute during drag - The event object will be sent to this function.
-* elementReference -
-* dragHandle -
-*
-*
-* Demos: (demo 1, The window widget), -* @version 1.0 -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ -DHTMLSuite.dragDropSimple = function(propertyArray){ - var divElement; - var dragTimer; // -1 no drag, 0-4 = initializing , 5 = drag in process - var cloneNode; - this.cloneNode = true; - - var callbackOnAfterDrag; - var callbackOnBeforeDrag; - var callbackOnDuringDrag; - - var mouse_x; - var mouse_y; - var positionSet; - var dragHandle; // If a specific element is specified to be a drag handle. - - var allowMoveX; - var allowMoveY; - var maxY; - var minY; - var minX; - var maxX; - - var initialXPos; - var initialYPos; - - this.positionSet = false; - this.dragHandle = new Array(); - var initOffsetX; - var initOffsetY; - - this.allowMoveX = true; - this.allowMoveY = true; - this.maxY = false; - this.maxX = false; - this.minX = false; - this.minY = false; - - this.callbackOnAfterDrag = false; - this.callbackOnBeforeDrag = false; - - this.dragStatus = -1; - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - var objectIndex; - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - this.__setInitProps(propertyArray); - this.__init(); -} - -DHTMLSuite.dragDropSimple.prototype = { - // {{{ __init() - /** - * Initializes the script - * - * @private - */ - __setInitProps : function(props){ - if(props.cloneNode===false || props.cloneNode)this.cloneNode=props.cloneNode; - if(props.allowMoveX===false || props.allowMoveX)this.allowMoveX=props.allowMoveX; - if(props.allowMoveY===false || props.allowMoveY)this.allowMoveY=props.allowMoveY; - if(props.minY || props.minY===0)this.minY=props.minY; - if(props.maxY || props.maxY===0)this.maxY=props.maxY; - if(props.minX || props.minX===0)this.minX=props.minX; - if(props.maxX || props.maxX===0)this.maxX=props.maxX; - - if(!props.initOffsetX)props.initOffsetX = 0; - if(!props.initOffsetY)props.initOffsetY = 0; - this.initOffsetX = props.initOffsetX; - this.initOffsetY = props.initOffsetY; - if(props.callbackOnBeforeDrag)this.callbackOnBeforeDrag = props.callbackOnBeforeDrag; - if(props.callbackOnAfterDrag)this.callbackOnAfterDrag = props.callbackOnAfterDrag; - if(props.callbackOnDuringDrag)this.callbackOnDuringDrag = props.callbackOnDuringDrag; - props.elementReference = DHTMLSuite.commonObj.getEl(props.elementReference); - this.divElement = props.elementReference; - this.initialXPos = DHTMLSuite.commonObj.getLeftPos(this.divElement); - this.initialYPos = DHTMLSuite.commonObj.getTopPos(this.divElement); - if(props.dragHandle)this.dragHandle[this.dragHandle.length] = DHTMLSuite.commonObj.getEl(props.dragHandle) - } - // }}} - , - // {{{ __init() - /** - * Initializes the script - * - * @private - */ - __init : function(){ - var ind = this.objectIndex; - this.divElement.objectIndex = ind; - this.divElement.setAttribute('objectIndex',ind); - this.divElement.style.padding = '0px'; - if(this.allowMoveX){ - this.divElement.style.left = (DHTMLSuite.commonObj.getLeftPos(this.divElement) + this.initOffsetX) + 'px'; - } - if(this.allowMoveY){ - this.divElement.style.top = (DHTMLSuite.commonObj.getTopPos(this.divElement) + this.initOffsetY) + 'px'; - } - this.divElement.style.position = 'absolute'; - this.divElement.style.margin = '0px'; - - if(this.divElement.style.zIndex && this.divElement.style.zIndex/1>DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=this.divElement.style.zIndex/1; - DHTMLSuite_dragDropSimple_curZIndex = DHTMLSuite_dragDropSimple_curZIndex/1 + 1; - this.divElement.style.zIndex = DHTMLSuite_dragDropSimple_curZIndex; - - if(this.cloneNode){ - var copy = this.divElement.cloneNode(true); - this.divElement.parentNode.insertBefore(copy,this.divElement); - copy.style.visibility = 'hidden'; - document.body.appendChild(this.divElement); - } - DHTMLSuite.commonObj.addEvent(this.divElement,'mousedown',function(e){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__initDragProcess(e); },ind); - DHTMLSuite.commonObj.addEvent(document.documentElement,'mousemove',function(e){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__moveDragableElement(e); },ind); - DHTMLSuite.commonObj.addEvent(document.documentElement,'mouseup',function(e){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__stopDragProcess(e); },ind); - if(!document.documentElement.onselectstart)document.documentElement.onselectstart = function() { return DHTMLSuite.commonObj.__isTextSelOk(); }; - } - // }}} - , - // {{{ setCallbackOnAfterDrag() - /** - * Specify name of function to execute after drag is completed. - * - * @param String functionName - Name of function to execute - * - * @private - */ - setCallbackOnAfterDrag : function(functionName){ - this.callbackOnAfterDrag = functionName; - } - // }}} - , - // {{{ setCallbackOnBeforeDrag() - /** - * Specify name of function to execute before drag is executed. - * - * @param String functionName - Name of function to execute - * - * @private - */ - setCallbackOnBeforeDrag : function(functionName){ - this.callbackOnBeforeDrag = functionName; - } - // }}} - , - // {{{ addDragHandle() - /** - * Specify a drag handle - * - * @param Object HTML Element - element inside the dragable element specified to act as a drag handle. - * - * @private - */ - addDragHandle : function(dragHandle){ - this.dragHandle[this.dragHandle.length] = dragHandle; - } - // }}} - , - // {{{ __initDragProcess() - /** - * Initializes drag process - * - * @private - */ - __initDragProcess : function(e){ - if(document.all)e = event; - var ind = this.objectIndex; - DHTMLSuite_dragDropSimple_curObjIndex = ind; - var thisObject = DHTMLSuite.variableStorage.arrayDSObjects[ind]; - if(!DHTMLSuite.commonObj.isObjectClicked(thisObject.divElement,e))return; - if(thisObject.divElement.style.zIndex && thisObject.divElement.style.zIndex/1>DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=thisObject.divElement.style.zIndex/1; - DHTMLSuite_dragDropSimple_curZIndex = DHTMLSuite_dragDropSimple_curZIndex/1 +1; - thisObject.divElement.style.zIndex = DHTMLSuite_dragDropSimple_curZIndex; - if(thisObject.callbackOnBeforeDrag){ - thisObject.__handleCallback('beforeDrag',e); - } - if(thisObject.dragHandle.length>0){ // Drag handle specified? - var objectFound; - for(var no=0;no=0 && this.dragTimer<5){ - this.dragTimer++; - setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].__waitBeforeDragProcessStarts()',5); - } - } - // }}} - , - // {{{ __moveDragableElement() - /** - * Move dragable element if drag is in process - * - * @param Event e - Event object - since this method is triggered by an event - * - * @private - */ - __moveDragableElement : function(e){ - if(document.all)e = event; - var ind = this.objectIndex; - var thisObj = DHTMLSuite.variableStorage.arrayDSObjects[ind]; - if(DHTMLSuite.clientInfoObj.isMSIE && e.button!=1)return thisObj.__stopDragProcess(); - if(thisObj.dragTimer==5){ - if(thisObj.allowMoveX){ - var leftPos = (e.clientX - this.mouse_x + this.el_x); - if(this.maxX!==false){ - if(leftPos + document.documentElement.scrollLeft>this.initialXPos+this.maxX){ - leftPos = this.initialXPos+this.maxX; - } - } - if(this.minX!==false){ - if(leftPos + document.documentElement.scrollLeftthis.initialYPos+this.maxY){ - topPos = this.initialYPos+this.maxY; - } - } - if(this.minY!==false){ - if(topPos DHTMLSuite_dragDropSimple_curZIndex){ - DHTMLSuite_dragDropSimple_curZIndex = zIndex/1+1; - } - } - -} - -/*[FILE_START:dhtmlSuite-dragDrop.js] */ -/************************************************************************************************************ -* Drag and drop class -* -* Created: August, 18th, 2006 -* -* Update log: -* -************************************************************************************************************/ -/** -* @constructor -* @class Purpose of class: A general drag and drop class. By creating objects of this class, you can make elements -* on your web page dragable and also assign actions to element when an item is dropped on it. -* A page should only have one object of this class.
-*
-* IMPORTANT when you use this class: Don't assign layout to the dragable element ids -* Assign it to classes or the tag instead. example: If you make
-* dragable, don't assign css to #dragableBox1. Assign it to div or .aBox instead.
-* (demo 1, demo 2), -* demo 3, demo 4 -* and demo 5) -* @version 1.0 -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.dragDrop = function(){ - var mouse_x; // mouse x position when drag is started - var mouse_y; // mouse y position when drag is started. - - var el_x; // x position of dragable element - var el_y; // y position of dragable element - - var dragDropTimer; // Timer - short delay from mouse down to drag init. - var numericIdToBeDragged; // numeric reference to element currently being dragged. - var dragObjCloneArray; // Array of cloned dragable elements. every - var dragDropSourcesArray; // Array of source elements, i.e. dragable elements. - var dragDropTargetArray; // Array of target elements, i.e. elements where items could be dropped. - var currentZIndex; // Current z index. incremented on each drag so that currently dragged element is always on top. - var okToStartDrag; // Variable which is true or false. It would be false for 1/100 seconds after a drag has been started. - // This is useful when you have nested dragable elements. It prevents the drag process from staring on - // parent element when you click on dragable sub element. - var moveBackBySliding; // Variable indicating if objects should slide into place moved back to their location without any slide animation. - var dragX_allowed; // Possible to drag this element along the x-axis? - var dragY_allowed; // Possible to drag this element along the y-axis? - - var currentEl_allowX; - var currentEl_allowY; - var drag_minX; - var drag_maxX; - var drag_minY; - var drag_maxY; - var dragInProgress; // Variable which is true when drag is in progress, false otherwise - - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - this.dragX_allowed = true; - this.dragY_allowed = true; - this.currentZIndex = 21000; - this.dragDropTimer = -1; - this.dragObjCloneArray = new Array(); - this.numericIdToBeDragged = false; - - this.okToStartDrag = true; - this.moveBackBySliding = true; - this.dragInProgress = false; - - var objectIndex; - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - -} - -DHTMLSuite.dragDrop.prototype = { - - // {{{ init() - /** - * Initialize the script - * This method should be called after you have added sources and destinations. - * - * @public - */ - init : function(){ - this.__initDragDropScript(); - } - // }}} - , - // {{{ addSource() - /** - * Add dragable element - * - * @param String sourceId = Id of source - * @param boolean slideBackAfterDrop = Slide the item back to it's original location after drop. - * @param boolean xAxis = Allowed to slide along the x-axis(default = true, i.e. if omitted). - * @param boolean yAxis = Allowed to slide along the y-axis(default = true, i.e. if omitted). - * @param String dragOnlyWithinElId = You will only allow this element to be dragged within the boundaries of the element with this id. - * - * @public - */ - addSource : function(sourceId,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId){ - if(!this.dragDropSourcesArray)this.dragDropSourcesArray = new Array(); - if(!document.getElementById(sourceId)){ - alert('The source element with id ' + sourceId + ' does not exists. Check your HTML code'); - return; - } - if(xAxis!==false)xAxis = true; - if(yAxis!==false)yAxis = true; - var obj = document.getElementById(sourceId); - this.dragDropSourcesArray[this.dragDropSourcesArray.length] = [obj,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId]; - obj.setAttribute('dragableElement',this.dragDropSourcesArray.length-1); - obj.dragableElement = this.dragDropSourcesArray.length-1; - - } - // }}} - , - // {{{ addTarget() - /** - * Add drop target - * - * @param String targetId = Id of drop target - * @param String functionToCallOnDrop = name of function to call on drop. - * Input to this the function specified in functionToCallOnDrop function would be - * id of dragged element - * id of the element the item was dropped on. - * mouse x coordinate when item was dropped - * mouse y coordinate when item was dropped - * - * @public - */ - addTarget : function(targetId,functionToCallOnDrop){ - if(!this.dragDropTargetArray)this.dragDropTargetArray = new Array(); - if(!document.getElementById(targetId))alert('The target element with id ' + targetId + ' does not exists. Check your HTML code'); - var obj = document.getElementById(targetId); - this.dragDropTargetArray[this.dragDropTargetArray.length] = [obj,functionToCallOnDrop]; - } - // }}} - , - // {{{ setSlide() - /** - * Activate or deactivate sliding animations. - * - * @param boolean isSlidingAnimationEnabled = Move element back to orig. location in a sliding animation - * - * @public - */ - setSlide : function(isSlidingAnimationEnabled){ - this.moveBackBySliding = isSlidingAnimationEnabled; - } - // }}} - , - /* Start private methods */ - - // {{{ __initDragDropScript() - /** - * Initialize drag drop script - this method is called by the init() method. - * - * @private - */ - __initDragDropScript : function(){ - var ind = this.objectIndex; - var refToThis = this; - var startIndex = Math.random() + ''; - startIndex = startIndex.replace('.','')/1; - - for(var no=0;no=0 && this.dragDropTimer<5){ - this.dragDropTimer = this.dragDropTimer + 1; - setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].__waitBeforeDragProcessStarts()',2); - return; - } - if(this.dragDropTimer>=5){ - if(this.dragObjCloneArray[this.numericIdToBeDragged].style.display=='none'){ - this.dragDropSourcesArray[this.numericIdToBeDragged][0].style.visibility = 'hidden'; - var ref = this.dragObjCloneArray[this.numericIdToBeDragged]; - ref.style.display = 'block'; - ref.style.visibility = 'visible'; - ref.style.top = DHTMLSuite.commonObj.getTopPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0]) + 'px'; - ref.style.left = DHTMLSuite.commonObj.getLeftPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0]) + 'px'; - } - } - } - // }}} - , - // {{{ __moveDragableElement() - /** - * Move dragable element according to mouse position when drag is in process. - * - * @param Event e = Event object, used to get x and y coordinate of mouse pointer - * - * @private - */ - __moveDragableElement : function(e){ - var ind = this.objectIndex; - if(document.all)e = event; - if(this.dragDropTimer<5)return false; - if(this.dragInProgress)return false; - this.dragInProgress = true; - var dragObj = this.dragObjCloneArray[this.numericIdToBeDragged]; - - if(this.currentEl_allowX){ - - var leftPos = (e.clientX - this.mouse_x + this.el_x); - if(this.drag_maxX){ - var tmpMaxX = this.drag_maxX - dragObj.offsetWidth; - if(leftPos > tmpMaxX)leftPos = tmpMaxX - if(leftPos < this.drag_minX)leftPos = this.drag_minX; - } - dragObj.style.left = leftPos + 'px'; - - } - if(this.currentEl_allowY){ - var topPos = (e.clientY - this.mouse_y + this.el_y); - if(this.drag_maxY){ - var tmpMaxY = this.drag_maxY - dragObj.offsetHeight; - if(topPos > tmpMaxY)topPos = tmpMaxY; - if(topPos < this.drag_minY)topPos = this.drag_minY; - } - dragObj.style.top = topPos + 'px'; - } - this.dragInProgress = false; - return false; - } - // }}} - , - // {{{ __stopDragProcess() - /** - * Drag process stopped. - * - * @param Event e = Event object, used to get x and y coordinate of mouse pointer - * - * @private - */ - __stopDragProcess : function(e){ - if(this.dragDropTimer<5)return false; - if(document.all)e = event; - - // Dropped on which element - var dropDestination = DHTMLSuite.commonObj.getSrcElement(e); - - var leftPosMouse = e.clientX + Math.max(document.body.scrollLeft,document.documentElement.scrollLeft); - var topPosMouse = e.clientY + Math.max(document.body.scrollTop,document.documentElement.scrollTop); - - if(!this.dragDropTargetArray)this.dragDropTargetArray = new Array(); - // Loop through drop targets and check if the coordinate of the mouse is over it. If it is, call specified drop function. - for(var no=0;no leftPosEl && leftPosMouse < (leftPosEl + widthEl) && topPosMouse > topPosEl && topPosMouse < (topPosEl + heightEl)){ - if(this.dragDropTargetArray[no][1]){ - try{ - eval(this.dragDropTargetArray[no][1] + '("' + this.dragDropSourcesArray[this.numericIdToBeDragged][0].id + '","' + this.dragDropTargetArray[no][0].id + '",' + e.clientX + ',' + e.clientY + ')'); - }catch(e){ - alert('Unable to execute \n' + this.dragDropTargetArray[no][1] + '("' + this.dragDropSourcesArray[this.numericIdToBeDragged][0].id + '","' + this.dragDropTargetArray[no][0].id + '",' + e.clientX + ',' + e.clientY + ')'); - } - } - break; - } - } - if(this.dragDropSourcesArray[this.numericIdToBeDragged][1]){ - this.__slideElementBackIntoItsOriginalPosition(this.numericIdToBeDragged); - } - // Variable cleanup after drop - this.dragDropTimer = -1; - DHTMLSuite.commonObj.__setTextSelOk(true); - this.numericIdToBeDragged = false; - } - // }}} - , - // {{{ __slideElementBackIntoItsOriginalPosition() - /** - * Slide an item back to it's original position - * - * @param Integer numId = numeric index of currently dragged element - * - * @private - */ - __slideElementBackIntoItsOriginalPosition : function(numId){ - // Coordinates current element position - var currentX = this.dragObjCloneArray[numId].style.left.replace('px','')/1; - var currentY = this.dragObjCloneArray[numId].style.top.replace('px','')/1; - - var ref = this.dragDropSourcesArray[numId][0]; - // Coordinates - where it should slide to - var targetX = DHTMLSuite.commonObj.getLeftPos(ref); - var targetY = DHTMLSuite.commonObj.getTopPos(ref);; - - if(this.moveBackBySliding){ - // Call the step by step slide method - this.__processSlideByPixels(numId,currentX,currentY,targetX,targetY); - }else{ - this.dragObjCloneArray[numId].style.display='none'; - ref.style.visibility = 'visible'; - } - } - // }}} - , - // {{{ __processSlideByPixels() - /** - * Move the element step by step in this method - * - * @param Int numId = numeric index of currently dragged element - * @param Int currentX = Elements current X position - * @param Int currentY = Elements current Y position - * @param Int targetX = Destination X position, i.e. where the element should slide to - * @param Int targetY = Destination Y position, i.e. where the element should slide to - * - * @private - */ - __processSlideByPixels : function(numId,currentX,currentY,targetX,targetY){ - // Find slide x value - var slideX = Math.round(Math.abs(Math.max(currentX,targetX) - Math.min(currentX,targetX)) / 10); - // Find slide y value - var slideY = Math.round(Math.abs(Math.max(currentY,targetY) - Math.min(currentY,targetY)) / 10); - - if(slideY<3 && Math.abs(slideX)<10)slideY = 3; // 3 is minimum slide value - if(slideX<3 && Math.abs(slideY)<10)slideX = 3; // 3 is minimum slide value - - if(currentX > targetX) slideX*=-1; // If current x is larger than target x, make slide value negative
- if(currentY > targetY) slideY*=-1; // If current y is larger than target x, make slide value negative - - // Update currentX and currentY - currentX = currentX + slideX; - currentY = currentY + slideY; - - // If currentX or currentY is close to targetX or targetY, make currentX equal to targetX(or currentY equal to targetY) - if(Math.max(currentX,targetX) - Math.min(currentX,targetX) < 4)currentX = targetX; - if(Math.max(currentY,targetY) - Math.min(currentY,targetY) < 4)currentY = targetY; - - // Update CSS position(left and top) - this.dragObjCloneArray[numId].style.left = currentX + 'px'; - this.dragObjCloneArray[numId].style.top = currentY + 'px'; - - // currentX different than targetX or currentY different than targetY, call this function in again in 5 milliseconds - if(currentX!=targetX || currentY != targetY){ - window.thisRef = this; // Reference to this dragdrop object - setTimeout('window.thisRef.__processSlideByPixels("' + numId + '",' + currentX + ',' + currentY + ',' + targetX + ',' + targetY + ')',5); - }else{ // Slide completed. Make absolute positioned element invisible and original element visible - this.dragObjCloneArray[numId].style.display='none'; - this.dragDropSourcesArray[numId][0].style.visibility = 'visible'; - } - } -} - -/*[FILE_START:dhtmlSuite-tabView.js] */ -/************************************************************************************************************ -* Tab view class -* -* Created: August, 21st, 2006 -* -* Update log: -* -************************************************************************************************************/ - -if(!window.DHTMLSuite)var DHTMLSuite=new Object();/************************************************************************************************************ -* Tab view class -* -* Created: August, 21st, 2006 -* -* Update log: -* -************************************************************************************************************/ - - -var refToTabViewObjects=new Array(); -// Reference to objects of this class. - -// We need this because the script doesn't allways know which object to use - -/** -* @constructor -* @class Purpose of class: Tab view class-transfors plain HTML into tabable layers.
-* (See demo 1 and demo 2) -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.tabView=function(){ - var textPadding; - // Tab spacing - var strictDocType ; - // Using a strict document type, i.e. - - var DHTMLSuite_tabObj; - // Reference to div surrounding the tab set - var activeTabIndex; - // Currently displayed tab(index-0=first tab) - var initActiveTabIndex; - // Initially displayed tab(index-0=first tab) - var ajaxObjects; - // Reference to ajax objects - var tabView_countTabs; - var tabViewHeight; - var tabSetParentId; - // Id of div surrounding the tab set. - var tabTitles; - // Tab titles - var width; - // width of tab view - var height; - // height of tab view - var layoutCSS; - var outsideObjectRefIndex; - // Which index of refToTabViewObjects refers to this object. - var maxNumberOfTabs; - var dynamicContentObj; - var closeButtons; - var refActiveTabContent; - - var callbackOnTabSwitch; - - this.initActiveTabIndex=0; - this.callbackOnTabSwitch=''; - this.refActiveTabContent=''; - - // Default variable values - this.textPadding=3; - this.strictDocType=true; - this.ajaxObjects=new Array(); - this.tabTitles=new Array(); - this.layoutCSS='tab-view.css'; - this.maxNumberOfTabs=6; - this.dynamicContentObj=false; - this.closeButtons=new Array(); - this.width='100%'; - this.height='500'; - - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); - // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } -} - -DHTMLSuite.tabView.prototype={ - - // {{{ init() - /** - *Initialize the script - * - *@public - */ - init:function() - { - DHTMLSuite.commonObj.loadCSS(this.layoutCSS); - this.outsideObjectRefIndex=refToTabViewObjects.length; - refToTabViewObjects[this.outsideObjectRefIndex]=this; - try{ - this.dynamicContentObj=new DHTMLSuite.dynamicContent(); - }catch(e){ - alert('You need to include DHTMLSuite-dynamicContent.js'); - } - this.__initializeAndParseTabs(false,false); - - } - - // }}} - , - - // {{{ setCallbackOnTabSwitch() - /** - *Set callback on tab switch - * - *@param String callbackOnTabSwitch=Name of function to execute when the user switches to a different tab. - * - *@public - */ - setCallbackOnTabSwitch:function(callbackOnTabSwitch) - { - this.callbackOnTabSwitch=callbackOnTabSwitch; - } - - // }}} - , - - // {{{ getMaximumNumberOfTabs() - /** - *Return maximum number of tabs - * - *@return Int maximumNumberOfTabs=Maximum number of tabs - * - *@public - */ - getMaximumNumberOfTabs:function() - { - return this.maxNumberOfTabs; - } - - // }}} - , - - // {{{ setMaximumTabs() - /** - *Set maximum number of tabs - * - *@param Int maximumNumberOfTabs=Maximum number of tabs - * - *@public - */ - setMaximumTabs:function(maximumNumberOfTabs) - { - this.maxNumberOfTabs=maximumNumberOfTabs; - } - - // }}} - , - - // {{{ setParentId() - /** - *Set padding on tabs - * - *@param String idOfParentHTMLElement=id of parent div - * - *@public - */ - setParentId:function(idOfParentHTMLElement) - { - this.tabSetParentId=idOfParentHTMLElement; - this.DHTMLSuite_tabObj=document.getElementById(idOfParentHTMLElement); - } - - // }}} - , - - // {{{ setWidth() - /** - *Set width of tab view - * - *@param String Width of tab view - * - *@public - */ - setWidth:function(newWidth) - { - this.width=newWidth; - } - - // }}} - , - - // {{{ setHeight() - /** - *Set height of tab view on tabs - * - *@param String Height of tab view - * - *@public - */ - setHeight:function(newHeight) - { - this.height=newHeight; - } - - // }}} - , - - // {{{ setIndexActiveTab() - /** - *Set index of initially active tab - * - *@param Int indexOfNewActiveTab=Index of active tab(0=first tab) - * - *@public - */ - setIndexActiveTab:function(indexOfNewActiveTab) - { - this.initActiveTabIndex=indexOfNewActiveTab; - } - - - // }}} - , - - // {{{ setTabTitles() - /** - *Set title of tabs - * - *@param Array titleOfTabs=Title of tabs - * - *@public - */ - setTabTitles:function(titleOfTabs) - { - this.tabTitles=titleOfTabs; - } - - - // }}} - , - - // {{{ setCloseButtons() - /** - *Specify which tabs that should have close buttons - * - *@param Array closeButtons=Array of true or false - * - *@public - */ - setCloseButtons:function(closeButtons) - { - this.closeButtons=closeButtons; - } - - // }}} - , - - // {{{ getReferenceToDivElement() - /** - * - *Returns a reference to the div element of a tab. - * - *@param String tabTitle=Title of tab - *@return Object Element to HTML div element for this tab. - * - *@public - */ - getReferenceToDivElementByTitle:function(tabTitle) - { - var index=this.getTabIndexByTitle(tabLabel); - // Get index of tab - if(index!=-1){ - var obj=document.getElementById('tabView'+this.tabSetParentId+'_'+index); - return obj; - } - return false; - } - - // }}} - , - - // {{{ getReferenceToDivElementById() - /** - * - *Returns a reference to the div element of a tab. - * - *@param String idOfTab=id of tab - *@return Object Element to HTML div element for this tab. - * - *@public - */ - getReferenceToDivElementById:function(idOfTab) - { - var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); - - for(var no=0;no-1 - this.displayATab(tabTitle,index); - return false; - } - if(this.tabView_countTabs>=this.maxNumberOfTabs)return; - // Maximum number of tabs reached-return - var div=document.createElement('DIV'); - // Create new tab content div. - div.className='DHTMLSuite_aTab'; - // Assign new tab to CSS class DHTMLSuite_aTab - this.DHTMLSuite_tabObj.appendChild(div); - // Appending new tab content div to main tab view div - var tabId=this.__initializeAndParseTabs(true,tabTitle,closeButton); - // Call the init method in order to create tab header and tab images - if(tabContent)div.innerHTML=tabContent; - // Static tab content specified, put it into the new div - if(tabContentUrl){ - // Get content from external file - this.dynamicContentObj.loadContent('tabView'+parentId +'_'+tabId,tabContentUrl); - } - // update tabTitles -- batur - this.tabTitles[tabId] = tabTitle; - - return true; - } - - - // }}} - , - - // {{{ deleteTab() - /** - * - *Delete a tab - * - *@param String tabLabel=Label of tab to delete(Optional) - *@param Int tabIndex=Index of tab to delete(Optional) - * - *@public - */ - deleteTab:function(tabLabel,tabIndex) - { - if(tabLabel){ - // Delete tab by tab title - var index=this.getTabIndexByTitle(tabLabel); - // Get index of tab - if(index!=-1){ - // Tab exists if index<>-1 - this.deleteTab(false,index); - } - - }else if(tabIndex>=0){ - // Delete tab by tab index. - if(document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex)){ - var obj=document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex); - var id=obj.parentNode.parentNode.id; - DHTMLSuite.discardElement(obj); - var obj2=document.getElementById('tabView'+this.tabSetParentId+'_'+tabIndex); - DHTMLSuite.discardElement(obj2); - this.__resetTabIds(this.tabSetParentId); - this.initActiveTabIndex=-1; - var newIndex=0; - if(refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex==tabIndex)refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex=-1; - this.__showTab(this.tabSetParentId,newIndex,this.outsideObjectRefIndex); - } - } - } - - // }}} - , - // {{{ addContentToTab() - /** - *Add content to a tab dynamically. - * - *@param String tabLabel=Label of tab to delete(Optional) - *@param String filePath=Path to file you want to show inside the tab. - * - *@public - */ - addContentToTab:function(tabLabel,filePath) - { - var index=this.getTabIndexByTitle(tabLabel); - // Get index of tab - if(index!=-1){ - // Tab found - this.dynamicContentObj.loadContent('tabView'+this.tabSetParentId+'_'+index,filePath); - } - } - - // }}} - , - - // {{{ displayATab() - /** - *Display a tab manually - * - *@param String tabTitle=Label of tab to show(Optional) - *@param Int tabIndex=Index of tab to show(Optional) - * - *@public - */ - - displayATab:function(tabLabel,tabIndex) - { - if(tabLabel){ - // Delete tab by tab title - var index=this.getTabIndexByTitle(tabLabel); - // Get index of tab - if(index!=-1){ - // Tab exists if index<>-1 - this.initActiveTabIndex=index; - }else return false; - - }else{ - this.initActiveTabIndex=tabIndex; - } - - this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex) - } - - // }}} - , - - // {{{ getTabIndex() - /** - *Return index of active tab - * - *@type Integer tabIndex=Index of active tab(0=first tab) - * - *@public - */ - getTabIndex:function() - { - var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); - var tabIndex=0; - for(var no=0;no=0){ - if(divs[no].className!='tabInactive')return tabIndex; - tabIndex++; - } - } - - //tabInactive - return tabIndex; - } - - // }}} - , - - - // {{{ __setPadding() - /** - *Set padding on tabs - * - *@private - */ - __setPadding:function(obj,padding){ - var span=obj.getElementsByTagName('SPAN')[0]; - span.style.paddingLeft=padding+'px'; - span.style.paddingRight=padding+'px'; - } - - // }}} - , - - // {{{ __showTab() - /** - *Set padding - * - *@param String parentId=id of parent div - *@param Int tabIndex=Index of tab to show - *@param Int objectIndex=Index of refToTabViewObjects, reference to the object of this class. - * - *@private - */ - __showTab:function(parentId,tabIndex,objectIndex) - { - var parentId_div=parentId+"_"; - if(!document.getElementById('tabView'+parentId_div+tabIndex)){ - return; - } - - if(refToTabViewObjects[objectIndex].activeTabIndex>=0){ - if(refToTabViewObjects[objectIndex].activeTabIndex==tabIndex){ - return; - } - var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex); - if(!obj){ - refToTabViewObjects[objectIndex].activeTabIndex=0; - var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex); - } - obj.className='tabInactive'; - obj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')'; - var imgs=obj.getElementsByTagName('IMG'); - var img=imgs[imgs.length-1]; - img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif'; - document.getElementById('tabView'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex).style.display='none'; - } - - var thisObj=document.getElementById('tabTab'+ parentId_div +tabIndex); - - thisObj.className='tabActive'; - thisObj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_active.gif'+'\')'; - var imgs=thisObj.getElementsByTagName('IMG'); - var img=imgs[imgs.length-1]; - img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_active.gif'; - - document.getElementById('tabView'+parentId_div+tabIndex).style.display='block'; - this.refActiveTabContent=document.getElementById('tabView'+parentId_div+tabIndex); - refToTabViewObjects[objectIndex].activeTabIndex=tabIndex; - - refToTabViewObjects[objectIndex].__handleCallback('tabSwitch'); - - var parentObj=thisObj.parentNode; - var aTab=parentObj.getElementsByTagName('DIV')[0]; - countObjects=0; - var startPos=2; - var previousObjectActive=false; - while(aTab){ - if(aTab.tagName=='DIV'){ - if(previousObjectActive){ - previousObjectActive=false; - startPos-=2; - } - if(aTab==thisObj){ - startPos-=2; - previousObjectActive=true; - refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding+1); - }else{ - refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding); - } - - aTab.style.left=startPos+'px'; - countObjects++; - startPos+=2; - } - aTab=aTab.nextSibling; - } - - return; - } - - // }}} - , - - // {{{ __handleCallback() - /** - *Set padding - * - *@param String action=Which call back action - * - *@private - */ - __handleCallback:function(action) - { - var callbackString=''; - switch(action) - { - case "tabSwitch": - callbackString=this.callbackOnTabSwitch; - break; - } - - if(callbackString){ - callbackString=callbackString+'(this.refActiveTabContent)'; - eval(callbackString); - } - } - - // }}} - , - - // {{{ tabClick() - /** - *Set padding - * - *@param String parentId=id of parent div - *@param Int tabIndex=Index of tab to show - * - *@private - */ - __tabClick:function(inputObj,index) - { - var idArray=inputObj.id.split('_'); - var parentId=inputObj.getAttribute('parentRefId'); - if(!parentId)parentId=inputObj.parentRefId; - this.__showTab(parentId,idArray[idArray.length-1].replace(/[^0-9]/gi,''),index); - - } - - // }}} - , - - // {{{ rolloverTab() - /** - *Set padding - * - * - *@private - */ - __rolloverTab:function() - { - if(this.className.indexOf('tabInactive')>=0){ - this.className='inactiveTabOver'; - this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_over.gif'+'\')'; - var imgs=this.getElementsByTagName('IMG'); - var img=imgs[imgs.length-1]; - - img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_over.gif'; - } - - } - - // }}} - , - - // {{{ rolloutTab() - /** - * - * - *@private - */ - __rolloutTab:function() - { - if(this.className== 'inactiveTabOver'){ - this.className='tabInactive'; - this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')'; - var imgs=this.getElementsByTagName('IMG'); - var img=imgs[imgs.length-1]; - img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif'; - } - } - - // }}} - , - - // {{{ __initializeAndParseTabs() - /** - * - *@param Int additionalTab=Additional tabs to the existing - *@param String nameOfAdditionalTab=Title of additional tab. - * - *@private - */ - __initializeAndParseTabs:function(additionalTab,nameOfAdditionalTab,additionalCloseButton) - { - this.DHTMLSuite_tabObj.className=' DHTMLSuite_tabWidget'; - - window.refToThisTabSet=this; - if(!additionalTab||additionalTab=='undefined'){ - this.DHTMLSuite_tabObj=document.getElementById(this.tabSetParentId); - this.width=this.width+''; - if(this.width.indexOf('%')<0)this.width= this.width+'px'; - this.DHTMLSuite_tabObj.style.width=this.width; - - this.height=this.height+''; - if(this.height.length>0){ - if(this.height.indexOf('%')<0)this.height= this.height+'px'; - this.DHTMLSuite_tabObj.style.height=this.height; - } - - var tabDiv=document.createElement('DIV'); - var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0]; - - this.DHTMLSuite_tabObj.insertBefore(tabDiv,firstDiv); - tabDiv.className='DHTMLSuite_tabContainer'; - this.tabView_countTabs=0; - var tmpTabTitles=this.tabTitles; - // tmpTab titles set to current tab titles-this variable is used in the loop below - - // We don't want to loop through all the tab titles in the object when we add a new one manually. - - }else{ - // A new tab being created dynamically afterwards. - var tabDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0]; - var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[1]; - this.initActiveTabIndex=this.tabView_countTabs; - var tmpTabTitles=Array(nameOfAdditionalTab); - // tmpTab titles set to only the new tab - } - for(var no=0;no0){ - if(this.height.indexOf('%')==-1){ - var tmpHeight=(this.height.replace('px','')/1-22); - tabs[no].style.height=tmpHeight+'px'; - }else - tabs[no].style.height=this.height; - } - tabs[no].style.display='none'; - if(tabs[no].id){ - tabs[no].setAttribute('originalId',tabs[no].id); - tabs[no].originalId=tabs[no].id; - } - tabs[no].id='tabView'+this.tabSetParentId+"_"+divCounter; - divCounter++; - } - } - if(additionalTab){ - this.tabView_countTabs++; - }else{ - this.tabView_countTabs=this.tabView_countTabs+this.tabTitles.length; - } - - this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex); - - return this.activeTabIndex; - } - - // }}} - , - - // {{{ __mouseOutEffectForCloseButton() - /** - * - *@private - */ - __mouseOutEffectForCloseButton:function() - { - this.src=this.src.replace('close-over.gif','close.gif'); - } - - // }}} - , - - // {{{ __mouseOverEffectCloseButton() - /** - * - *@private - */ - __mouseOverEffectCloseButton:function() - { - this.src=this.src.replace('close.gif','close-over.gif'); - } - - // }}} - , - - // {{{ __fillTabWithContentFromAjax() - /** - * - *@param Int ajaxIndex=Index of Ajax array - *@param String objId=Id of element where content from Ajax should be displayed - *@param Int tabId=Id of element where content from Ajax should be displayed - * - *@private - */ - __fillTabWithContentFromAjax:function(ajaxIndex,objId,tabId) - { - var obj=document.getElementById('tabView'+objId+'_'+tabId); - obj.innerHTML=this.ajaxObjects[ajaxIndex].response; - } - - // }}} - , - - // {{{ __resetTabIds() - /** - * - *@private - */ - __resetTabIds:function(parentId) - { - var tabTitleCounter=0; - var tabContentCounter=0; - var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); - - for(var no=0;no=0&&divs[no].parentNode.parentNode==this.DHTMLSuite_tabObj){ - divs[no].id='tabTab'+parentId+'_'+tabContentCounter; - tabContentCounter++; - } - - } - this.tabView_countTabs=tabContentCounter; - } - - // }}} - , - - // {{{ getTabIndexByTitle() - /** - * - *@private - */ - getTabIndexByTitle:function(tabTitle) - { - tabTitle=tabTitle.replace(/(.*?) .*$/gi,'$1'); - var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); - - for(var no=0;no=0){ - var span=divs[no].getElementsByTagName('SPAN')[0]; - var spanTitle=span.innerHTML.replace(/(.*?) .*$/gi,'$1'); - if(spanTitle==tabTitle){ - var tmpId=divs[no].id.split('_'); - return tmpId[tmpId.length-1].replace(/[^0-9]/g,'')/1; - } - } - } - return -1; - } - , - // batur - // {{{ getTabTitle() - /** - * return active tab title - *@public - */ - getTabTitle:function() { - return (this.tabTitles[this.activeTabIndex]); - } - - // }}} -} - -/*[FILE_START:dhtmlSuite-dragDropTree.js] */ -/************************************************************************************************************ -* Drag and drop folder tree -* -* Created: August, 23rd, 2006 -* -* Demos of this class: demo-drag-drop-folder-tree.html -* -* Update log: -* -************************************************************************************************************/ - -var JSTreeObj; -var treeUlCounter = 0; -var nodeId = 1; - -/** -* @constructor -* @class Purpose of class: Transforms an UL,LI list into a folder tree with drag and drop capabilities(See demo). -* @version 1.0 -* @version 1.0 -* -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.JSDragDropTree = function(){ - var idOfTree; - var folderImage; - var plusImage; - var minusImage; - var maximumDepth; - var dragNode_source; - var dragNode_parent; - var dragNode_sourceNextSib; - var dragNode_noSiblings; - - var dragNode_destination; - var floatingContainer; - var dragDropTimer; - var dropTargetIndicator; - var insertAsSub; - var indicator_offsetX; - var indicator_offsetX_sub; - var indicator_offsetY; - var messageMaximumDepthReached; - var ajaxObjects; - var layoutCSS; - var cookieName; - - /* Initial variable values */ - this.folderImage = 'DHTMLSuite_folder.gif'; - this.plusImage = 'DHTMLSuite_plus.gif'; - this.minusImage = 'DHTMLSuite_minus.gif'; - this.maximumDepth = 6; - this.layoutCSS = 'drag-drop-folder-tree.css'; - - this.floatingContainer = document.createElement('UL'); - this.floatingContainer.style.position = 'absolute'; - this.floatingContainer.style.display='none'; - this.floatingContainer.id = 'floatingContainer'; - this.insertAsSub = false; - document.body.appendChild(this.floatingContainer); - this.dragDropTimer = -1; - this.dragNode_noSiblings = false; - this.cookieName = 'DHTMLSuite_expandedNodes'; - - if(document.all){ - this.indicator_offsetX = 1; // Offset position of small black lines indicating where nodes would be dropped. - this.indicator_offsetX_sub = 1; - this.indicator_offsetY = 13; - }else{ - this.indicator_offsetX = 1; // Offset position of small black lines indicating where nodes would be dropped. - this.indicator_offsetX_sub = 3; - this.indicator_offsetY = 5; - } - if(navigator.userAgent.indexOf('Opera')>=0){ - this.indicator_offsetX = 2; // Offset position of small black lines indicating where nodes would be dropped. - this.indicator_offsetX_sub = 3; - this.indicator_offsetY = -7; - } - - this.messageMaximumDepthReached = ''; // Use '' if you don't want to display a message - this.ajaxObjects = new Array(); - - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - var objectIndex; - - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - -} - -/* DHTMLSuite.JSDragDropTree class */ -DHTMLSuite.JSDragDropTree.prototype = { - // {{{ init() - /** - * Initializes the script - * - * @public - */ - init : function(){ - var ind = this.objectIndex; - DHTMLSuite.commonObj.loadCSS(this.layoutCSS); - JSTreeObj = this; - this.__createDropIndicator(); - if(!document.documentElement.onselectstart)document.documentElement.onselectstart = function() { return DHTMLSuite.commonObj.__isTextSelOk(); }; - document.documentElement.ondragstart = document.documentElement.ondragstart = function() { return false; }; - DHTMLSuite.commonObj.__addEventEl(document.documentElement); - var nodeId = 0; - var DHTMLSuite_tree = document.getElementById(this.idOfTree); - var menuItems = DHTMLSuite_tree.getElementsByTagName('LI'); // Get an array of all menu items - for(var no=0;no0 && subItems[0].style.display!='block'){ - this.showHideNode(false,menuItems[no].id); - } - } - } - // }}} - , - // {{{ collapseAll() - /** - * Collapse all tree nodes - * - * - * @public - */ - collapseAll : function(){ - var menuItems = document.getElementById(this.idOfTree).getElementsByTagName('LI'); - for(var no=0;no0 && subItems[0].style.display=='block'){ - this.showHideNode(false,menuItems[no].id); - } - } - } - // }}} - , - // {{{ showHideNode() - /** - * Expand a specific node - * - * @param boolean e - If you call this method manually, set this argument to false(It's not used) - * @param string inputId - Id of node to expand/collapse - * - * @public - */ - showHideNode : function(e,inputId){ - if(inputId){ - if(!document.getElementById(inputId))return; - thisNode = document.getElementById(inputId).getElementsByTagName('IMG')[0]; - }else { - if(document.all)e = event; - var srcEl = DHTMLSuite.commonObj.getSrcElement(e); - thisNode = srcEl; - if(srcEl.tagName=='A')thisNode = srcEl.parentNode.getElementsByTagName('IMG')[0]; - } - if(thisNode.style.visibility=='hidden')return; - var parentNode = thisNode.parentNode; - inputId = parentNode.id.replace(/[^0-9]/g,''); - if(thisNode.src.indexOf(this.plusImage)>=0){ - thisNode.src = thisNode.src.replace(this.plusImage,this.minusImage); - var ul = parentNode.getElementsByTagName('UL')[0]; - ul.style.display='block'; - if(!initExpandedNodes)initExpandedNodes = ','; - if(initExpandedNodes.indexOf(',' + inputId + ',')<0) initExpandedNodes = initExpandedNodes + inputId + ','; - }else{ - thisNode.src = thisNode.src.replace(this.minusImage,this.plusImage); - parentNode.getElementsByTagName('UL')[0].style.display='none'; - initExpandedNodes = initExpandedNodes.replace(',' + inputId,''); - } - DHTMLSuite.commonObj.setCookie(this.cookieName,initExpandedNodes,500); - return false; - } - // }}} - , - // {{{ getSaveString() - /** - * Return save string - * - * @param Object initObj - Only for private use inside the method - * @param String saveString - Only for private use inside the method - you should call this method without arguments. - * - * @return String saveString - A string with the format id-parentId,id-parentId,id-parentId - * @type String - * @public - */ - getSaveString : function(initObj,saveString){ - if(!saveString)var saveString = ''; - if(!initObj){ - initObj = document.getElementById(this.idOfTree); - - } - var lis = initObj.getElementsByTagName('LI'); - - if(lis.length>0){ - var li = lis[0]; - while(li){ - if(li.id){ - if(saveString.length>0)saveString = saveString + ','; - saveString = saveString + li.id.replace(/[^0-9]/gi,''); - saveString = saveString + '-'; - if(li.parentNode.id!=this.idOfTree)saveString = saveString + li.parentNode.parentNode.id.replace(/[^0-9]/gi,''); else saveString = saveString + '0'; - - var ul = li.getElementsByTagName('UL'); - if(ul.length>0){ - saveString = this.getSaveString(ul[0],saveString); - } - } - li = li.nextSibling; - } - } - if(initObj.id == this.idOfTree){ - return saveString; - } - return saveString; - } - // }}} - , - // {{{ __initializeDragProcess() - /** - * Init a drag process - * - * @param event e = Event object - * @private - */ - __initializeDragProcess : function(e){ - if(document.all)e = event; - - var subs = JSTreeObj.floatingContainer.getElementsByTagName('LI'); - if(subs.length>0){ - if(JSTreeObj.dragNode_sourceNextSib){ - JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib); - }else{ - JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source); - } - } - - JSTreeObj.dragNode_source = this.parentNode; - JSTreeObj.dragNode_parent = this.parentNode.parentNode; - JSTreeObj.dragNode_sourceNextSib = false; - - if(JSTreeObj.dragNode_source.nextSibling)JSTreeObj.dragNode_sourceNextSib = JSTreeObj.dragNode_source.nextSibling; - JSTreeObj.dragNode_destination = false; - JSTreeObj.dragDropTimer = 0; - DHTMLSuite.commonObj.__setTextSelOk(false); - JSTreeObj.__waitBeforeDragProcessStarts(); - return false; - } - // }}} - , - // {{{ __waitBeforeDragProcessStarts() - /** - * A small delay before drag is started - * - * @private - */ - __waitBeforeDragProcessStarts : function(){ - if(this.dragDropTimer>=0 && this.dragDropTimer<10){ - this.dragDropTimer = this.dragDropTimer + 1; - setTimeout('JSTreeObj.__waitBeforeDragProcessStarts()',20); - return; - } - if(this.dragDropTimer==10){ - JSTreeObj.floatingContainer.style.display='block'; - JSTreeObj.floatingContainer.appendChild(JSTreeObj.dragNode_source); - } - } - // }}} - , - // {{{ __moveDragableNodes() - /** - * Move dragable nodes - * @param event e - Event object - * - * @private - */ - __moveDragableNodes : function(e,tagType){ - if(JSTreeObj.dragDropTimer<10)return; - if(document.all)e = event; - dragDrop_x = e.clientX/1 + 5 + document.body.scrollLeft; - dragDrop_y = e.clientY/1 + 5 + document.documentElement.scrollTop; - - JSTreeObj.floatingContainer.style.left = dragDrop_x + 'px'; - JSTreeObj.floatingContainer.style.top = dragDrop_y + 'px'; - - var thisObj = DHTMLSuite.commonObj.getSrcElement(e); - var thisObjOrig = DHTMLSuite.commonObj.getSrcElement(e); - if(thisObj.tagName=='A' || thisObj.tagName=='IMG')thisObj = thisObj.parentNode; - - JSTreeObj.dragNode_noSiblings = false; - var tmpVar = thisObj.getAttribute('noSiblings'); - if(!tmpVar)tmpVar = thisObj.noSiblings; - if(tmpVar=='true')JSTreeObj.dragNode_noSiblings=true; - - if(thisObj && tagType){ - JSTreeObj.dragNode_destination = thisObj; - var img = thisObj.getElementsByTagName('IMG')[1]; - var tmpObj= JSTreeObj.dropTargetIndicator; - tmpObj.style.display='block'; - - var eventSourceObj = thisObjOrig; - if(JSTreeObj.dragNode_noSiblings && eventSourceObj.tagName=='IMG')eventSourceObj = eventSourceObj.nextSibling; - - var tmpImg = tmpObj.getElementsByTagName('IMG')[0]; - if(thisObjOrig.tagName=='A' || JSTreeObj.dragNode_noSiblings){ - tmpImg.src = tmpImg.src.replace('ind1','ind2'); - JSTreeObj.insertAsSub = true; - tmpObj.style.left = (DHTMLSuite.commonObj.getLeftPos(eventSourceObj) + JSTreeObj.indicator_offsetX_sub) + 'px'; - }else{ - - tmpImg.src = tmpImg.src.replace('ind2','ind1'); - JSTreeObj.insertAsSub = false; - tmpObj.style.left = (DHTMLSuite.commonObj.getLeftPos(eventSourceObj) + JSTreeObj.indicator_offsetX) + 'px'; - } - - tmpObj.style.top = (DHTMLSuite.commonObj.getTopPos(thisObj) + JSTreeObj.indicator_offsetY) + 'px'; - } - - return false; - - } - // }}} - , - // {{{ __dropDragableNodes() - /** - * Drag process ended - drop nodes - * - * @private - */ - __dropDragableNodes:function(){ - if(JSTreeObj.dragDropTimer<10){ - JSTreeObj.dragDropTimer = -1; - DHTMLSuite.commonObj.__setTextSelOk(true); - return; - } - var showMessage = false; - if(JSTreeObj.dragNode_destination){ // Check depth - var countUp = JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_destination,'up'); - var countDown = JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_source,'down'); - var countLevels = countUp/1 + countDown/1 + (JSTreeObj.insertAsSub?1:0); - - if(countLevels>JSTreeObj.maximumDepth){ - JSTreeObj.dragNode_destination = false; - showMessage = true; // Used later down in this function - } - } - - if(JSTreeObj.dragNode_destination){ - if(JSTreeObj.insertAsSub){ - var uls = JSTreeObj.dragNode_destination.getElementsByTagName('UL'); - if(uls.length>0){ - ul = uls[0]; - ul.style.display='block'; - - var lis = ul.getElementsByTagName('LI'); - - if(lis.length>0){ // Sub elements exists - drop dragable node before the first one - ul.insertBefore(JSTreeObj.dragNode_source,lis[0]); - }else { // No sub exists - use the appendChild method - This line should not be executed unless there's something wrong in the HTML, i.e empty
    - ul.appendChild(JSTreeObj.dragNode_source); - } - }else{ - var ul = document.createElement('UL'); - ul.style.display='block'; - JSTreeObj.dragNode_destination.appendChild(ul); - ul.appendChild(JSTreeObj.dragNode_source); - } - var img = JSTreeObj.dragNode_destination.getElementsByTagName('IMG')[0]; - img.style.visibility='visible'; - img.src = img.src.replace(JSTreeObj.plusImage,JSTreeObj.minusImage); - - }else{ - if(JSTreeObj.dragNode_destination.nextSibling){ - var nextSib = JSTreeObj.dragNode_destination.nextSibling; - nextSib.parentNode.insertBefore(JSTreeObj.dragNode_source,nextSib); - }else{ - JSTreeObj.dragNode_destination.parentNode.appendChild(JSTreeObj.dragNode_source); - } - } - /* Clear parent object */ - var tmpObj = JSTreeObj.dragNode_parent; - var lis = tmpObj.getElementsByTagName('LI'); - if(lis.length==0){ - var img = tmpObj.parentNode.getElementsByTagName('IMG')[0]; - img.style.visibility='hidden'; // Hide [+],[-] icon - DHTMLSuite.discardElement(tmpObj); - } - }else{ - // Putting the item back to it's original location - - if(JSTreeObj.dragNode_sourceNextSib){ - JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib); - }else{ - JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source); - } - - } - JSTreeObj.dropTargetIndicator.style.display='none'; - JSTreeObj.dragDropTimer = -1; - DHTMLSuite.commonObj.__setTextSelOk(true); - if(showMessage && JSTreeObj.messageMaximumDepthReached)alert(JSTreeObj.messageMaximumDepthReached); - } - // }}} - , - // {{{ __createDropIndicator() - /** - * Create small black lines indicating where items will be dropped - * - * @private - */ - __createDropIndicator : function(){ - this.dropTargetIndicator = document.createElement('DIV'); - this.dropTargetIndicator.style.zIndex = 240000; - this.dropTargetIndicator.style.position = 'absolute'; - this.dropTargetIndicator.style.display='none'; - var img = document.createElement('IMG'); - img.src = DHTMLSuite.configObj.imagePath + 'drag-drop-tree/' + 'dragDrop_ind1.gif'; - img.id = 'dragDropIndicatorImage'; - this.dropTargetIndicator.appendChild(img); - document.body.appendChild(this.dropTargetIndicator); - } - // }}} - , - // {{{ __getDepthOfABranchInTheTree() - /** - * Count depth of a branch - * - * @private - */ - __getDepthOfABranchInTheTree : function(obj,direction,stopAtObject){ - var countLevels = 0; - if(direction=='up'){ - while(obj.parentNode && obj.parentNode!=stopAtObject){ - obj = obj.parentNode; - if(obj.tagName=='UL')countLevels = countLevels/1 +1; - } - return countLevels; - } - - if(direction=='down'){ - var subObjects = obj.getElementsByTagName('LI'); - for(var no=0;nodemo). -* @version 1.0 -* @version 1.0 -* -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.ajaxUtil = function(){ - var ajaxObjects; - this.ajaxObjects = new Array(); - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - var objectIndex; - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - -} - -DHTMLSuite.ajaxUtil.prototype = { - // {{{ sendRequest() - /** - * Sends an ajax request to the server - * - * @param String url = Path on the server - * @param String paramString - Parameters, Example: "varA=2&varB=3"; - * @param String functionNameOnComplete = Function to execute on complete, example: "myFunction". The ajax object will be sent to this function and you can get the response from the "reponse" attribute. - * NB! This ajax object will be cleared automatically by the script after a 3 second delay. - * - * @public - */ - sendRequest : function(url,paramString,functionNameOnComplete){ - var ind = this.objectIndex; - var ajaxIndex = this.ajaxObjects.length; - try{ - this.ajaxObjects[ajaxIndex] = new sack(); - }catch(e){ - alert('Could not create ajax object. Please make sure that ajax.js is included'); - } - if(paramString){ - var params = this.__getArrayByParamString(paramString); - for(var no=0;nodemo).
    -* The pane splitter, window widget and the ajax tooltip script are also using this class to put external content into HTML elements. -* @version 1.0 -* @version 1.0 -* -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -**/ - -DHTMLSuite.dynamicContent = function(){ - var enableCache; // Cache enabled. - var jsCache; - var ajaxObjects; - var waitMessage; - - this.enableCache = true; - this.jsCache = new Object(); - this.ajaxObjects = new Array(); - this.waitMessage = 'Loading content - please wait...'; - this.waitImage = 'dynamic-content/ajax-loader-darkblue.gif'; - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - var objectIndex; - - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - -} - -DHTMLSuite.dynamicContent.prototype = { - - // {{{ loadContent() - /** - * Load content from external files into an element on your web page. - * - * @param String divId = Id of HTML element - * @param String url = Path to content on the server(Local content only) - * @param String functionToCallOnLoaded = Function to call when ajax is finished. This string will be evaulated, example of string: "fixContent()" (with the quotes). - * - * @public - */ - loadContent : function(divId,url,functionToCallOnLoaded){ - - var ind = this.objectIndex; - if(this.enableCache && this.jsCache[url]){ - document.getElementById(divId).innerHTML = this.jsCache[url]; - DHTMLSuite.commonObj.__evaluateJs(divId); - DHTMLSuite.commonObj.__evaluateCss(divId); - if(functionToCallOnLoaded)eval(functionToCallOnLoaded); - return; - } - var ajaxIndex = 0; - - /* Generating please wait message */ - var waitMessageToShow = ''; - if(this.waitImage){ // Wait image exists ? - waitMessageToShow = waitMessageToShow + '
    '; - } - if(this.waitMessage){ // Wait message exists ? - waitMessageToShow = waitMessageToShow + '
    ' + this.waitMessage + '
    '; - } - - if(this.waitMessage!=null && this.waitImage!=null){ - try{ - if(waitMessageToShow.length>0)document.getElementById(divId).innerHTML=waitMessageToShow; - }catch(e){ - } - } - waitMessageToShow = false; - var ajaxIndex = this.ajaxObjects.length; - - try{ - this.ajaxObjects[ajaxIndex] = new sack(); - }catch(e){ - alert('Could not create ajax object. Please make sure that ajax.js is included'); - } - - if(url.indexOf('?')>=0){ // Get variables in the url - this.ajaxObjects[ajaxIndex].method='GET'; // Change method to get - var string = url.substring(url.indexOf('?')); // Extract get variables - url = url.replace(string,''); - string = string.replace('?',''); - var items = string.split(/&/g); - for(var no=0;no tag. - * - * @public - */ - setCache : function(enableCache){ - this.enableCache = enableCache; - } - // }}} - , - // {{{ __ajax_showContent() - /** - * Evaluate Javascript in the inserted content - * - * @private - */ - __ajax_showContent :function(divId,ajaxIndex,url,functionToCallOnLoaded){ - document.getElementById(divId).innerHTML = ''; - document.getElementById(divId).innerHTML = this.ajaxObjects[ajaxIndex].response; - if(this.enableCache){ // Cache is enabled - this.jsCache[url] = document.getElementById(divId).innerHTML + ''; // Put content into cache - } - DHTMLSuite.commonObj.__evaluateJs(divId); // Call private method which evaluates JS content - DHTMLSuite.commonObj.__evaluateCss(divId); // Call private method which evaluates JS content - if(functionToCallOnLoaded)eval(functionToCallOnLoaded); - this.ajaxObjects[ajaxIndex] = null; // Clear sack object - return false; - } - // }}} - , - // {{{ __ajax_displayError() - /** - * Display error message when the request failed. - * - * @private - */ - __ajax_displayError : function(divId,ajaxIndex,url,functionToCallOnLoaded){ - document.getElementById(divId).innerHTML = '

    Message from DHTMLSuite.dynamicContent

    The ajax request for ' + url + ' failed

    '; - } - // }}} -} - -/*[FILE_START:dhtmlSuite-slider.js] */ -/************************************************************************************************************ -* -* DHTML slider -* -* Created: August, 25th, 2006 -* @class Purpose of class: Display a slider on a web page. -* -* Demos of this class: demo-slider-1.html -* -* Update log: -* -************************************************************************************************************/ - -DHTMLSuite.sliderObjects = new Array(); // Array of slider objects. Used in events when "this" refers to the tag trigger the event and not the object. -DHTMLSuite.indexOfCurrentlyActiveSlider = false; // Index of currently active slider(i.e. index in the DHTMLSuite.sliderObjects array) -DHTMLSuite.slider_generalMouseEventsAdded = false; // Only assign mouse move and mouseup events once. This variable make sure that happens. - -/** -* @constructor -* @class Purpose of class: Display a DHTML slider on a web page. This slider could either be displayed horizontally or vertically(demo 1 and demo 2). -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -* -**/ -DHTMLSuite.slider = function(){ - var width; // Width of slider - var height; // height of slider - var targetObj; // Object where slider will be added. - var sliderWidth; // Width of slider image. this is needed in order to position the slider and calculate values correctly. - var sliderDirection; // Horizontal or vertical - var functionToCallOnChange; // Function to call when the slider is moved. - var layoutCss; - var sliderMaxValue; // Maximum value to return from slider - var sliderMinValue; // Minimum value to return from slider - var initialValue; // Initial value of slider - var sliderSize; // Size of sliding area. - var directionOfPointer; // Direction of slider pointer; - var slideInProcessTimer; // Private variable used to determine if slide is in progress or not. - var indexThisSlider; // Index of object in the DHTMLSuite.sliderObjects array - var numberOfSteps; // Hardcoded steps - var stepLinesVisibility; // Visibility of lines indicating where the slider steps are - - var slide_event_pos; // X position of mouse when slider drag starts - var slide_start_pos; // X position of slider when drag starts - var sliderHandleImg; // Reference to the small slider handle - var sliderName; // A name you can use to identify a slider. Useful if you have more than one slider, but only one onchange event. - var sliderValueReversed; // Variable indicating if the value of the slider is reversed(i.e. max at left and min at right) - this.sliderWidth = 9; // Initial width of slider. - this.layoutCss = 'slider.css'; // Default css file - this.sliderDirection = 'hor'; // Horizontal is default - this.width = 0; // Initial widht - this.height = 0; // Initial height - this.sliderMaxValue = 100; // Default max value to return from slider - this.sliderMinValue = 0; // Default min value to return from slider - this.initialValue = 0; // Default initial value of slider - this.targetObj = false; // Set target obj to false initially. - this.directionOfPointer = 'up'; // Default pointer direction for slider handle. - this.slideInProcessTimer = -1; - this.sliderName = ''; - this.numberOfSteps = false; - this.stepLinesVisibility = true; - this.sliderValueReversed = false; // Default value of sliderValueReversed, i.e. max at right, min at left or max at top, min at bottom. - - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - var objectIndex; - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - -} - -DHTMLSuite.slider.prototype = { - - // {{{ init() - /** - * Initializes the script, i.e. creates the slider - * - * - * @public - */ - - init : function() // Initializes the script - { - if(!this.targetObj){ - alert('Error! - No target for slider specified'); - return; - } - - this.__setWidthAndHeightDynamically(); - DHTMLSuite.commonObj.loadCSS(this.layoutCss); - this.__createSlider(); - if(!document.documentElement.onselectstart)document.documentElement.onselectstart = function() { return DHTMLSuite.commonObj.__isTextSelOk(); }; - - } - // }}} - , - // {{{ setSliderTarget(divId) - /** - * Specify where to insert the slider - * - * @param Object targetRef - Id of element where the slider will be created inside(There shouldn't be any content inside this div) - * - * @public - */ - setSliderTarget : function(targetRef){ - targetRef = DHTMLSuite.commonObj.getEl(targetRef); - this.targetObj = targetRef; - } - // }}} - , - // {{{ setSliderDirection(newDirection) - /** - * Specify where to insert the slider - * - * @param String newDirection - New slider direction. Possible valuse: "hor" or "ver" - * - * @public - */ - setSliderDirection : function(newDirection){ - newDirection = newDirection + ''; - newDirection = newDirection.toLowerCase(); - if(newDirection!='hor' && newDirection!='ver'){ - alert('Invalid slider direction - possible values: "hor" or "ver"'); - return; - } - this.sliderDirection = newDirection; - } - // }}} - , - // {{{ setSliderWidth(newWidth) - /** - * Specify width of slider - if now width is specified, the script will try to measure the height of width of the element where it is inserted. - * - * @param String newWidth - Slider width(numeric or percentage) example: 100 or 90% - * - * @public - */ - setSliderWidth : function(newWidth){ - newWidth = newWidth + ''; - if(newWidth.indexOf('%')==-1)newWidth = newWidth + 'px'; - this.width = newWidth; - } - // }}} - , - // {{{ setSliderHeight(newHeight) - /** - * Specify height of slider - if now width is specified, the script will try to measure the height of width of the element where it is inserted. - * - * @param String newHeight - Slider width(numeric or percentage) example: 100 or 90% - * - * @public - */ - setSliderHeight : function(newHeight){ - newHeight = newHeight + ''; - if(newHeight.indexOf('%')==-1)newHeight = newHeight + 'px'; - this.height = height; - } - // }}} - , - // {{{ setSliderReversed() - /** - * Reverse slider, i.e. max at left instead of right or at bottom instead of top - * - * - * @public - */ - setSliderReversed : function(){ - this.sliderValueReversed = true; - } - // }}} - , - // {{{ setOnChangeEvent(nameOfFunction) - /** - * Specify which function to call when the slider has been moved. - * - * @param String nameOfFunction - Name of function to call. - * - * @public - */ - setOnChangeEvent : function(nameOfFunction){ - this.functionToCallOnChange = nameOfFunction; - - } - // }}} - , - // {{{ setSliderMaxValue(newMaxValue) - /** - * Set maximum value of slider - * - * @param int newMaxValue - New slider max value - * - * @public - */ - setSliderMaxValue : function(newMaxValue){ - this.sliderMaxValue = newMaxValue; - - } - // }}} - , - // {{{ setSliderMinValue(newMinValue) - /** - * Set minimum value of slider - * - * @param int newMinValue - New slider min value - * - * @public - */ - setSliderMinValue : function(newMinValue){ - this.sliderMinValue = newMinValue; - - } - // }}} - , - // {{{ setSliderName(nameOfSlider) - /** - * Specify name of slider. - * - * @param String nameOfSlider - Name of function to call. - * - * @public - */ - setSliderName : function(nameOfSlider){ - this.sliderName = nameOfSlider; - - } - // }}} - , - // {{{ setLayoutCss(nameOfNewCssFile) - /** - * Specify a new CSS file for the slider(i.e. not using default css file which is slider.css) - * - * @param String nameOfNewCssFile - Name of new css file. - * - * @public - */ - setLayoutCss : function(nameOfNewCssFile){ - this.layoutCss = nameOfNewCssFile; - } - // }}} - , - // {{{ setLayoutCss(nameOfNewCssFile) - /** - * Specify a new CSS file for the slider(i.e. not using default css file which is slider.css) - * - * @param String nameOfNewCssFile - Name of new css file. - * - * @public - */ - setInitialValue : function(newInitialValue){ - this.initialValue = newInitialValue; - } - // }}} - , - // {{{ setSliderPointerDirection(directionOfPointer) - /** - * In which direction should the slider handle point. - * - * @param String directionOfPointer - In which direction should the slider handle point(possible values: 'up','down','left','right' - * - * @public - */ - setSliderPointerDirection : function(directionOfPointer){ - this.directionOfPointer = directionOfPointer; - } - // }}} - , - // {{{ setSliderValue(newValue) - /** - * Set new position of slider manually - * - * @param Int newValue - New value of slider - * - * @public - */ - setSliderValue : function(newValue){ - var position = Math.floor((newValue / this.sliderMaxValue) * this.sliderSize); - if(this.sliderDirection=='hor'){ - this.sliderHandleImg.style.left = position + 'px'; - }else{ - this.sliderHandleImg.style.top = position + 'px'; - } - } - // }}} - , - // {{{ setNumberOfSliderSteps(numberOfSteps) - /** - * Divide slider into steps, i.e. instead of having a smooth slide. - * - * @param Int numberOfSteps - Number of steps - * - * @public - */ - setNumberOfSliderSteps : function(numberOfSteps){ - this.numberOfSteps = numberOfSteps; - } - // }}} - , - // {{{ setStepLinesVisible(visible) - /** - * Divide slider into steps. - * - * @param Boolean visible - When using static steps, make lines indicating steps visible or hidden(true = visible(default), false = hidden) - * - * @public - */ - setStepLinesVisible : function(visible){ - this.stepLinesVisibility = visible; - } - // }}} - , - // {{{ __setWidthAndHeightDynamically() - /** - * Automatically set height and width of slider. - * - * - * @private - */ - __setWidthAndHeightDynamically : function(){ - // No width or height specified - try to measure it from the size of parent box - - if(!this.width || this.width==0)this.width = this.targetObj.clientWidth+''; - if(!this.height || this.height==0)this.height = this.targetObj.clientHeight+''; - if(!this.width || this.width==0)this.width = this.targetObj.offsetWidth+''; - if(!this.height || this.height==0)this.height = this.targetObj.offsetHeight+''; - - if(this.width==0)return; - if(this.height==0)return; - - if(this.width.indexOf('px')==-1 && this.width.indexOf('%')==-1)this.width = this.width + 'px'; - if(this.height.indexOf('px')==-1 && this.height.indexOf('%')==-1)this.height = this.height + 'px'; - - } - // }}} - , - // {{{ __createSlider() - /** - * Creates the HTML for the slider dynamically - * - * - * @private - */ - __createSlider : function(initWidth){ - if(this.targetObj.clientWidth==0 || initWidth==0){ - var timeoutTime = 100; - setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + this.objectIndex + '].__createSlider(' + this.targetObj.clientWidth + ')',timeoutTime); - return; - } - this.__setWidthAndHeightDynamically(); - this.indexThisSlider = DHTMLSuite.sliderObjects.length; - DHTMLSuite.sliderObjects[this.indexThisSlider] = this; - - window.refToThisObject = this; - - // Creates a parent div for the slider - var div = document.createElement('DIV'); - - div.style.width = this.width; - div.style.cursor = 'default'; - div.style.height = this.height; - div.style.position = 'relative'; - div.id = 'sliderNumber' + this.indexThisSlider; // the numeric part of this id is used inside the __setPositionFromClick method - div.onmousedown = this.__setPositionFromClick; - DHTMLSuite.commonObj.__addEventEl(div); - this.targetObj.appendChild(div); - - var sliderObj = document.createElement('DIV'); - - if(this.sliderDirection=='hor'){ // Horizontal slider. - sliderObj.className='DHTMLSuite_slider_horizontal'; - sliderObj.style.width = div.clientWidth + 'px'; - this.sliderSize = div.offsetWidth - this.sliderWidth; - - // Creating slider handle image. - var sliderHandle = document.createElement('IMG'); - var srcHandle = 'slider_handle_down.gif'; - sliderHandle.style.bottom = '2px'; - if(this.directionOfPointer=='up'){ - srcHandle = 'slider_handle_up.gif'; - sliderHandle.style.bottom = '0px'; - } - sliderHandle.src = DHTMLSuite.configObj.imagePath + 'slider/' + srcHandle; - div.appendChild(sliderHandle); - - // Find initial left position of slider - var leftPos; - if(this.sliderValueReversed){ - leftPos = Math.round(((this.sliderMaxValue - this.initialValue) / this.sliderMaxValue) * this.sliderSize) -1; - }else{ - leftPos = Math.round((this.initialValue / this.sliderMaxValue) * this.sliderSize); - } - sliderHandle.style.left = leftPos + 'px'; - - }else{ - sliderObj.className='DHTMLSuite_slider_vertical'; - sliderObj.style.height = div.clientHeight + 'px'; - this.sliderSize = div.clientHeight - this.sliderWidth; - - // Creating slider handle image. - var sliderHandle = document.createElement('IMG'); - var srcHandle = 'slider_handle_right.gif'; - sliderHandle.style.left = '0px'; - if(this.directionOfPointer=='left'){ - srcHandle = 'slider_handle_left.gif'; - sliderHandle.style.left = '0px'; - } - sliderHandle.src = DHTMLSuite.configObj.imagePath + 'slider/' + srcHandle; - div.appendChild(sliderHandle); - - // Find initial left position of slider - var topPos; - if(!this.sliderValueReversed){ - topPos = Math.floor(((this.sliderMaxValue - this.initialValue) / this.sliderMaxValue) * this.sliderSize); - }else{ - topPos = Math.floor((this.initialValue / this.sliderMaxValue) * this.sliderSize); - } - - sliderHandle.style.top = topPos + 'px'; - - } - - sliderHandle.id = 'sliderForObject' + this.indexThisSlider; - sliderHandle.style.position = 'absolute'; - sliderHandle.style.zIndex = 5; - sliderHandle.onmousedown = this.__initializeSliderDrag; - sliderHandle.ondragstart = function() { return false; }; - sliderHandle.onselectstart = function() { return false; }; - DHTMLSuite.commonObj.__addEventEl(sliderHandle); - this.sliderHandleImg = sliderHandle; - - if(!DHTMLSuite.slider_generalMouseEventsAdded){ - // Adding onmousemove event to the tag - DHTMLSuite.commonObj.addEvent(document.documentElement,"mousemove",this.__moveSlider); - // Adding onmouseup event to the tag. - DHTMLSuite.commonObj.addEvent(document.documentElement,"mouseup",this.__stopSlideProcess); - DHTMLSuite.slider_generalMouseEventsAdded = true; - } - - sliderObj.innerHTML = ''; // In order to get a correct height/width of the div - div.appendChild(sliderObj); - - if(this.numberOfSteps && this.stepLinesVisibility){ // Number of steps defined, create graphical lines - var stepSize = this.sliderSize / this.numberOfSteps; - for(var no=0;no<=this.numberOfSteps;no++){ - var lineDiv = document.createElement('DIV'); - lineDiv.style.position = 'absolute'; - lineDiv.innerHTML = ''; - div.appendChild(lineDiv); - if(this.sliderDirection=='hor'){ - lineDiv.className='DHTMLSuite_smallLines_vertical'; - lineDiv.style.left = Math.floor((stepSize * no) + (this.sliderWidth/2)) + 'px'; - }else{ - lineDiv.className='DHTMLSuite_smallLines_horizontal'; - lineDiv.style.top = Math.floor((stepSize * no) + (this.sliderWidth/2)) + 'px'; - lineDiv.style.left = '14px'; - } - - } - } - - } - // }}} - , - // {{{ __initializeSliderDrag() - /** - * Init slider drag - * - * - * @private - */ - __initializeSliderDrag : function(e){ - if(document.all)e = event; - DHTMLSuite.commonObj.__setTextSelOk(false); - var numIndex = this.id.replace(/[^0-9]/gi,''); // Get index in the DHTMLSuite.sliderObject array. We get this from the id of the slider image(i.e. "this"). - var sliderObj = DHTMLSuite.sliderObjects[numIndex]; - DHTMLSuite.indexOfCurrentlyActiveSlider = numIndex; - sliderObj.slideInProcessTimer = 0; - if(sliderObj.sliderDirection=='hor'){ - sliderObj.slide_event_pos = e.clientX; // Get start x position of mouse pointer - sliderObj.slide_start_pos = this.style.left.replace('px','')/1; // Get x position of slider - }else{ - sliderObj.slide_event_pos = e.clientY; // Get start x position of mouse pointer - sliderObj.slide_start_pos = this.style.top.replace('px','')/1; // Get x position of slider - } - - sliderObj.__waitBeforeSliderDragStarts(); - return false; // Firefox need this line. - } - // }}} - , - // {{{ __setPositionFromClick() - /** - * Set position from click - click on slider - move handle to the mouse pointer - * - * - * @private - */ - __setPositionFromClick : function(e){ - if(document.all)e = event; - // Tag of element triggering this event. If it's something else than a
    , return without doing anything, i.e. mouse down on slider handle. - if (e.target) srcEvent = e.target; - else if (e.srcElement) srcEvent = e.srcElement; - if (srcEvent.nodeType == 3) // defeat Safari bug - srcEvent = srcEvent.parentNode; - if(srcEvent.tagName!='DIV')return; - - var numIndex = this.id.replace(/[^0-9]/gi,''); // Get index in the DHTMLSuite.sliderObject array. We get this from the id of the slider image(i.e. "this"). - var sliderObj = DHTMLSuite.sliderObjects[numIndex]; - - if(sliderObj.numberOfSteps){ - modValue = sliderObj.sliderSize / sliderObj.numberOfSteps; // Find value to calculate modulus by - } - - if(sliderObj.sliderDirection=='hor'){ - var handlePos = (e.clientX - DHTMLSuite.commonObj.getLeftPos(this) - Math.ceil(sliderObj.sliderWidth/2)); - }else{ - var handlePos = (e.clientY - DHTMLSuite.commonObj.getTopPos(this) - Math.ceil(sliderObj.sliderWidth/2)); - } - if(sliderObj.numberOfSteps){ // Static steps defined - var mod = handlePos % modValue; // Calculate modulus - if(mod>(modValue/2))mod = modValue-mod; else mod*=-1; // Should we move the slider handle left or right? - handlePos = handlePos + mod; - } - if(handlePos<0)handlePos = 0; // Don't allow negative values - if(handlePos > sliderObj.sliderSize)handlePos = sliderObj.sliderSize; // Don't allow values larger the slider size - - if(sliderObj.sliderDirection=='hor'){ - sliderObj.sliderHandleImg.style.left = handlePos + 'px'; - if(!sliderObj.sliderValueReversed){ - returnValue = Math.round((handlePos/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); - }else{ - returnValue = Math.round(((sliderObj.sliderSize - handlePos)/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); - } - }else{ - sliderObj.sliderHandleImg.style.top = handlePos + 'px'; - if(sliderObj.sliderValueReversed){ - returnValue = Math.round((handlePos/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); - }else{ - returnValue = Math.round(((sliderObj.sliderSize - handlePos)/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); - } - } - returnValue = returnValue + sliderObj.sliderMinValue; - - - if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange + '(' + returnValue + ',"' + sliderObj.sliderName + '","click")'); - - DHTMLSuite.indexOfCurrentlyActiveSlider = numIndex; - sliderObj.slideInProcessTimer = 10; - if(sliderObj.sliderDirection=='hor'){ - sliderObj.slide_event_pos = e.clientX; // Get start x position of mouse pointer - sliderObj.slide_start_pos = handlePos; // Get x position of slider - }else{ - sliderObj.slide_event_pos = e.clientY; // Get start x position of mouse pointer - sliderObj.slide_start_pos = handlePos; // Get x position of slider - } - DHTMLSuite.commonObj.__setTextSelOk(false); - - } - // }}} - , - // {{{ __waitBeforeSliderDragStarts() - /** - * A small delay before the drag process starts. - * - * - * @private - */ - __waitBeforeSliderDragStarts : function(){ - if(this.slideInProcessTimer<10 && this.slideInProcessTimer>=0){ - this.slideInProcessTimer+=2; - window.refToThisSlider = this; - setTimeout('window.refToThisSlider.__waitBeforeSliderDragStarts()',5); - } - - } - // }}} - , - // {{{ __moveSlider() - /** - * Move the slider - * - * - * @private - */ - __moveSlider : function(e){ - if(DHTMLSuite.indexOfCurrentlyActiveSlider===false)return; - var sliderObj = DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider]; - if(document.all)e = event; - if(sliderObj.slideInProcessTimer<10)return; - - var returnValue = sliderObj.__getSliderValue(e); - - - if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange + '(' + returnValue + ',"' + sliderObj.sliderName + '","move")'); - - } - , - __getSliderValue : function(e) { - var returnValue; - // Static steps defined ? - if(this.numberOfSteps){ // Find value to calculate modulus by - modValue = this.sliderSize / this.numberOfSteps; - } - if(this.sliderDirection=='hor'){ - var handlePos = e.clientX - this.slide_event_pos + this.slide_start_pos; - }else{ - var handlePos = e.clientY - this.slide_event_pos + this.slide_start_pos; - } - if(this.numberOfSteps){ - var mod = handlePos % modValue; - if(mod>(modValue/2))mod = modValue-mod; else mod*=-1; - handlePos = handlePos + mod; - } - if(handlePos<0)handlePos = 0; - if(handlePos > this.sliderSize)handlePos = this.sliderSize; - - if(this.sliderDirection=='hor'){ - this.sliderHandleImg.style.left = handlePos + 'px'; - if(!this.sliderValueReversed){ - returnValue = Math.round((handlePos/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); - }else{ - returnValue = Math.round(((this.sliderSize - handlePos)/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); - } - }else{ - this.sliderHandleImg.style.top = handlePos + 'px'; - if(this.sliderValueReversed){ - returnValue = Math.round((handlePos/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); - }else{ - returnValue = Math.round(((this.sliderSize - handlePos)/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); - } - } - returnValue = returnValue + this.sliderMinValue; - return returnValue; - - } - // }}} - , - // {{{ __stopSlideProcess() - /** - * Stop the drag process - * - * - * @private - */ - __stopSlideProcess : function(e){ - if(document.all)e = event; - DHTMLSuite.commonObj.__setTextSelOk(true); - if(!DHTMLSuite.indexOfCurrentlyActiveSlider)return; - var sliderObj = DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider]; - sliderObj.slideInProcessTimer = -1; - var returnValue = sliderObj.__getSliderValue(e); - if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange + '(' + returnValue + ',"' + sliderObj.sliderName + '","mouseup")'); - } -} - -/*[FILE_START:dhtmlSuite-modalMessage.js] */ -/************************************************************************************************************ -* DHTML modal dialog box -* -* Created: August, 26th, 2006 -* @class Purpose of class: Display a modal dialog box on the screen. -* -* Css files used by this script: modal-message.css -* -* Demos of this class: demo-modal-message-1.html -* -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class Purpose of class: Display a modal DHTML message on the page. All other page controls will be disabled until the message is closed(demo). -* @param Array - Associative array of properties. These properties can also be set by calling invidiual set-methods. Possible keys in this array:
    -* url - Url to file displayed in the message -* htmlOfModalMessage - Static HTML to display. -* domRef - Reference to dom element. This dom element will be cloned and displayed inside the message box. You will typically set display:none or visibility:hidden on this element -* width - Width of box -* height - Height of box -* cssClassOfMessageBox - Alternative css class for the message box -* shadowOffset - Size of drop shadow in pixels -* shadowDivVisible - Shadow visible (default = true) -* isModal - Is the dialog modal ? (default = true) -* -* @version 1.0 -* @author Alf Magne Kalleland(www.dhtmlgoodies.com) -*/ - -DHTMLSuite.modalMessage = function(props){ - var url; // url of modal message - var htmlOfModalMessage; // html of modal message - var domRef; // Reference to DOM element - - var divs_transparentDiv; // Transparent div covering page content - var divs_content; // Modal message div. - var iframeEl; // Iframe element used to cover select boxes in ie - var layoutCss; // Name of css file; - var width; // Width of message box - var height; // Height of message box - var isModal; // Is the modal message modal ? - - var existingBodyOverFlowStyle; // Existing body overflow css - var dynContentObj; // Reference to dynamic content object - var cssClassOfMessageBox; // Alternative css class of message box - in case you want a different appearance on one of them - var shadowDivVisible; // Shadow div visible ? - var shadowOffset; // X and Y offset of shadow(pixels from content box) - - var objectIndex; - - this.url = ''; // Default url is blank - this.htmlOfModalMessage = ''; // Default message is blank - this.layoutCss = 'modal-message.css'; // Default CSS file - this.height = 200; // Default height of modal message - this.width = 400; // Default width of modal message - this.cssClassOfMessageBox = false; // Default alternative css class for the message box - this.shadowDivVisible = true; // Shadow div is visible by default - this.shadowOffset = 5; // Default shadow offset. - this.isModal = true; - - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - var ind = this.objectIndex; - - DHTMLSuite.commonObj.addEvent(window,"resize",function() { DHTMLSuite.variableStorage.arrayDSObjects[ind].__resizeTransparentDiv(); }); - - if(props)this.__setInitialProps(props); -} - -DHTMLSuite.modalMessage.prototype = { - // {{{ __setInitialProps - /** - * Save properties sent to the constructor. - * - * @private - */ - __setInitialProps : function(props){ - if(props.url)this.setSource(props.url); - if(props.htmlOfModalMessage)this.setHtmlContent(props.htmlOfModalMessage); - if(props.domRef)this.setDomReference(props.domRef); - if(props.width)this.width = props.width; - if(props.height)this.height = props.height; - if(props.cssClassOfMessageBox)this.cssClassOfMessageBox = props.cssClassOfMessageBox; - if(props.shadowOffset)this.shadowOffset = props.shadowOffset; - if(props.shadowDivVisible)this.shadowDivVisible = props.shadowDivVisible; - if(props.isModal || props.isModal===false || props.isModal===0)this.isModal = props.isModal; - if(props.waitMessage)this.setWaitMessage(waitMessage); - } - // }}} - , - // {{{ setIsModal(urlOfSource) - /** - * Specify if the box should be modal, i.e. a transparent div behind the box covering page content. - * - * @public - */ - setIsModal : function(isModal){ - this.isModal = isModal; - } - // }}} - , - // {{{ setSource(urlOfSource) - /** - * Set source of the modal dialog box - * - * - * @public - */ - setSource : function(urlOfSource){ - if(urlOfSource)this.__clearProperties(); - this.url = urlOfSource; - } - // }}} - , - // {{{ setHtmlContent(newHtmlContent) - /** - * Setting static HTML content for the modal dialog box. - * - * @param String newHtmlContent = Static HTML content of box - * - * @public - */ - setHtmlContent : function(newHtmlContent){ - if(newHtmlContent)this.__clearProperties(); - this.htmlOfModalMessage = newHtmlContent; - } - // }}} - , - // {{{ setDomReference - /** - * Specify reference to DOM element which will be displayed inside the modal message box. - * - * @param Object domRef = Dom reference - * - * @public - */ - setDomReference : function(domRef){ - if(domRef)this.__clearProperties(); - if(domRef)domRef = DHTMLSuite.commonObj.getEl(domRef); - if(domRef){ - domRef = domRef.cloneNode(true); - } - this.domRef = domRef; - } - // }}} - , - // {{{ setSize - /** - * Set the size of the modal dialog box - * - * @param int width = width of box - * @param int height = height of box - * - * @public - */ - setSize : function(width,height){ - if(width)this.width = width; - if(height)this.height = height; - } - // }}} - , - // {{{ setCssClassMessageBox(newCssClass) - /** - * Assign the message box to a new css class.(in case you wants a different appearance on one of them) - * - * @param String newCssClass = Name of new css class (Pass false if you want to change back to default) - * - * @public - */ - setCssClassMessageBox : function(newCssClass){ - this.cssClassOfMessageBox = newCssClass; - if(this.divs_content){ - if(this.cssClassOfMessageBox) - this.divs_content.className=this.cssClassOfMessageBox; - else - this.divs_content.className='modalDialog_contentDiv'; - } - - } - // }}} - , - // {{{ setShadowOffset(newShadowOffset) - /** - * Specify the size of shadow - * - * @param Int newShadowOffset = Offset of shadow div(in pixels from message box - x and y) - * - * @public - */ - setShadowOffset : function(newShadowOffset){ - this.shadowOffset = newShadowOffset - - } - // }}} - , - // {{{ setWaitMessage(newMessage) - /** - * Set a wait message when Ajax is busy inserting content - * - * @param String newMessage = New wait message - * - * @public - */ - setWaitMessage : function(newMessage){ - if(!this.dynContentObj){ - try{ - this.dynContentObj = new DHTMLSuite.dynamicContent(); // Creating dynamic content object if it doesn't already exist. - }catch(e){ - alert('You need to include dhtmlSuite-dynamicContent.js'); - } - } - this.dynContentObj.setWaitMessage(newMessage); // Calling the DHTMLSuite.dynamicContent setWaitMessage - } - // }}} - , - // {{{ setWaitImage(newImage) - /** - * Set a wait Image when Ajax is busy inserting content - * - * @param String newImage = New wait Image - * - * @public - */ - setWaitImage : function(newImage){ - if(!this.dynContentObj){ - try{ - this.dynContentObj = new DHTMLSuite.dynamicContent(); // Creating dynamic content object if it doesn't already exist. - }catch(e){ - alert('You need to include dhtmlSuite-dynamicContent.js'); - } - } - this.dynContentObj.setWaitImage(newImage); // Calling the DHTMLSuite.dynamicContent setWaitImage - } - // }}} - , - // {{{ setCache() - /** - * Enable or disable cache for the ajax object - * - * @param Boolean cacheStatus = false = off, true = on - * - * @public - */ - setCache : function(cacheStatus){ - if(!this.dynContentObj){ - try{ - this.dynContentObj = new DHTMLSuite.dynamicContent(); // Creating dynamic content object if it doesn't already exist. - }catch(e){ - alert('You need to include dhtmlSuite-dynamicContent.js'); - } - } - this.dynContentObj.setCache(cacheStatus); // Calling the DHTMLSuite_dynamicContent setCache - - } - // }}} - , - // {{{ display() - /** - * Display the modal dialog box - * - * - * @public - */ - display : function(){ - var ind = this.objectIndex; - - if(!this.divs_transparentDiv){ - DHTMLSuite.commonObj.loadCSS(this.layoutCss); - this.__createDivElements(); - } - this.__resizeAndPositionDivElements(); - // Redisplaying divs - if(this.isModal){ - this.divs_transparentDiv.style.display='block'; - }else{ - this.divs_transparentDiv.style.display='none'; - } - this.divs_content.style.display='block'; - this.divs_shadow.style.display='block'; - - if(this.iframeEl){ - setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].iframeEl.style.display="block"',150); - } - - this.__resizeAndPositionDivElements(); - - /* Call the __resizeAndPositionDivElements method twice in case the css file has changed. The first execution of this method may not catch these changes */ - window.refToThisModalBoxObj = this; - setTimeout('window.refToThisModalBoxObj.__resizeAndPositionDivElements()',100); - - this.__addHTMLContent(); // Calling method which inserts content into the message div. - } - // }}} - , - // {{{ () - /** - * Display the modal dialog box - * - * - * @public - */ - setShadowDivVisible : function(visible){ - this.shadowDivVisible = visible; - } - // }}} - , - // {{{ close() - /** - * Close the modal dialog box - * - * - * @public - */ - close : function(){ - document.documentElement.style.overflow = ''; // Setting the CSS overflow attribute of the tag back to default. - /* Hiding divs */ - this.divs_transparentDiv.style.display='none'; - this.divs_content.style.display='none'; - this.divs_shadow.style.display='none'; - if(this.iframeEl)this.iframeEl.style.display='none'; - - } - // }}} - , - // {{{ __clearProperties() - /** - * Clear content properties - * - * - * @private - */ - __clearProperties : function(){ - if(this.domRef)DHTMLSuite.discardElement(this.domRef); - this.domRef = null; - this.url = false; - this.htmlOfModalMessage = false; - } - // }}} - , - // {{{ __createDivElements() - /** - * Create the divs for the modal dialog box - * - * - * @private - */ - __createDivElements : function(){ - // Creating transparent div - this.divs_transparentDiv = document.createElement('DIV'); - this.divs_transparentDiv.className='DHTMLSuite_modalDialog_transparentDivs'; - this.divs_transparentDiv.style.left = '0px'; - this.divs_transparentDiv.style.top = '0px'; - this.divs_transparentDiv.id='transparentDiv'; - document.body.appendChild(this.divs_transparentDiv); - // Creating content div - if(!document.getElementById('DHTMLSuite_modalBox_contentDiv')){ - this.divs_content = document.createElement('DIV'); - this.divs_content.className = 'DHTMLSuite_modalDialog_contentDiv'; - this.divs_content.id = 'DHTMLSuite_modalBox_contentDiv'; - document.body.appendChild(this.divs_content); - }else{ - this.divs_content = document.getElementById('DHTMLSuite_modalBox_contentDiv'); - } - // Creating shadow div - this.divs_shadow = document.createElement('DIV'); - this.divs_shadow.className = 'DHTMLSuite_modalDialog_contentDiv_shadow'; - document.body.appendChild(this.divs_shadow); - - if(DHTMLSuite.clientInfoObj.isMSIE){ - this.iframeEl = document.createElement(''; - this.formRef.method = this.method; - this.formRef.action = this.action; - this.formRef.target = this.iframeName; - if(!this.formRef.enctype)this.formRef.enctype = 'multipart/form-data'; - - } - // }}} - , - // {{{ __getIframeResponse() - /** - * Form has been submitted to iframe - move content from iframe - * - * @private - */ - __getIframeResponse : function(){ - if(this.responseEl){ - if(this.responseFile){ - if(!this.responseEl.id)this.responseEl.id = 'DHTMLSuite_formResponse' + DHTMLSuite.getUniqueId(); - var dynContent = new DHTMLSuite.dynamicContent(); - dynContent.loadContent(this.responseEl.id,this.responseFile); - }else{ - this.responseEl.innerHTML = self.frames[this.iframeName].document.body.innerHTML; - DHTMLSuite.commonObj.__evaluateJs(this.responseEl); - DHTMLSuite.commonObj.__evaluateCss(this.responseEl); - } - } - this.coverDiv.style.display='none'; - this.__handleCallback('onComplete'); - } - // }}} - , - // {{{ __positionCoverDiv() - /** - * Position cover div - * - * @private - */ - __positionCoverDiv : function(){ - if(!this.responseEl)return; - try{ - var st = this.coverDiv.style; - st.left = DHTMLSuite.commonObj.getLeftPos(this.responseEl) + 'px'; - st.top = DHTMLSuite.commonObj.getTopPos(this.responseEl) + 'px'; - st.width = this.responseEl.offsetWidth + 'px'; - st.height = this.responseEl.offsetHeight + 'px'; - st.display='block'; - }catch(e){ - } - } - // }}} - , - // {{{ __createCoverDiv() - /** - * Submits the form - * - * @private - */ - __createCoverDiv : function(){ - if(this.coverDiv)return; - this.coverDiv = document.createElement('DIV'); - var el = this.coverDiv; - el.style.overflow='hidden'; - el.style.zIndex = 1000; - el.style.position = 'absolute'; - - document.body.appendChild(el); - - var innerDiv = document.createElement('DIV'); - innerDiv.style.width='105%'; - innerDiv.style.height='105%'; - innerDiv.className = 'DHTMLSuite_formCoverDiv'; - innerDiv.style.opacity = '0.2'; - innerDiv.style.filter = 'alpha(opacity=20)'; - el.appendChild(innerDiv); - - var ajaxLoad = document.createElement('DIV'); - ajaxLoad.className = 'DHTMLSuite_formCoverDiv_ajaxLoader'; - el.appendChild(ajaxLoad); - } - // }}} - , - // {{{ __createSackObject() - /** - * Create new sack object - * - * @private - */ - __createSackObject : function(ajaxIndex){ - var ind = this.objectIndex; - this.sackObj[ajaxIndex] = new sack(); - this.sackObj[ajaxIndex].requestFile = this.action; - this.sackObj[ajaxIndex].method = this.method; - this.sackObj[ajaxIndex].onCompletion = function(){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__getResponse(ajaxIndex); } - } - // }}} - , - // {{{ __getResponse() - /** - * Get response from ajax - * - * @private - */ - __getResponse : function(ajaxIndex){ - - if(this.responseEl){ - if(this.responseFile){ - if(!this.responseEl.id)this.responseEl.id = 'DHTMLSuite_formResponse' + DHTMLSuite.getUniqueId(); - var dynContent = new DHTMLSuite.dynamicContent(); - dynContent.loadContent(this.responseEl.id,this.responseFile); - }else{ - this.responseEl.innerHTML = this.sackObj[ajaxIndex].response; - DHTMLSuite.commonObj.__evaluateJs(this.responseEl); - DHTMLSuite.commonObj.__evaluateCss(this.responseEl); - } - } - - this.coverDiv.style.display='none'; - this.sackObj[ajaxIndex] = null; - this.__handleCallback('onComplete'); - } - // }}} - , - // {{{ __populateSack() - /** - * Populate sack object with form data - * @param ajaxIndex - index of current sack object - * - * @private - */ - __populateSack : function(ajaxIndex){ - var els = this.formUtil.getValuesAsArray(this.formRef); - for(var prop in els){ - if(DHTMLSuite.commonObj.isArray(els[prop])){ - for(var no=0;no=0){ // The name of the form field is already indicating an array - name = prop.replace('[','[' + no); - } - this.sackObj[ajaxIndex].setVar(name,els[prop][no]); - } - }else{ - this.sackObj[ajaxIndex].setVar(prop,els[prop]); - } - } - } - // }}} - , - // {{{ __setInitProperties() - /** - * Fill object with data sent to the constructor - * @param Array props - Associative Array("Object") of properties - * - * @private - */ - __setInitProperties : function(props){ - if(props.formRef)this.formRef = DHTMLSuite.commonObj.getEl(props.formRef); - if(props.method)this.method = props.method; - if(props.responseEl)this.responseEl = DHTMLSuite.commonObj.getEl(props.responseEl); - if(props.action)this.action = props.action; - if(props.responseFile)this.responseFile = props.responseFile; - if(props.callbackOnComplete)this.callbackOnComplete = props.callbackOnComplete; - if(!this.action)this.action = this.formRef.action; - if(!this.method)this.method = this.formRef.method; - } - // }}} - , - // {{{ __handleCallback() - /** - * Execute callback - * @param String action - Which callback action - * - * @private - */ - __handleCallback : function(action){ - var callbackString = ''; - switch(action){ - case "onComplete": - callbackString = this.callbackOnComplete; - break; - - } - if(callbackString){ - if(callbackString.indexOf('(')==-1)callbackString = callbackString + '("' + this.formRef.name + '")'; - eval(callbackString); - } - - } -} - -/*[FILE_START:dhtmlSuite-autoComplete.js] */ -/************************************************************************************************************ -* DHTML auto complete script -* -* Created: Jun, 06th, 2007 -* @module coder: Batur Orkun (batur@bilkent.edu.tr, http://www.xdhtml.com) -* -* @class Purpose of class: this script shows you a list of options based on what you type into a text input. - Example: Type in "A" and Ajax will get you a list of all contries starting with "A". -* -* Css files used by this script: auto-complete.css -* -* Demos of this class: demo-auto-complete.html -* -* Update log: -* -************************************************************************************************************/ - -/** -* @constructor -* @class Purpose of class: this script shows you a list of options based on what you type into a text input. -* @version 0.1 -* @author Alf Magne Kalleland & Batur Orkun -* (www.dhtmlgoodies.com) -*/ - -DHTMLSuite.autoComplete=function(){ - // definations - var layoutCss; - var ajaxBox_offsetX; - var ajaxBox_offsetY; - var minimumLettersBeforeLookup; // Number of letters entered before a lookup is performed. - - var ajax_list_currentLetters; - var ajax_list_cachedLists - var ajax_optionDiv; - var ajax_list_MSIE; - var ajax_list_activeItem; - var ajax_list_objects; - var ajax_list_activeInput; - var ajax_list_activeItem; - var ajax_list_optionDivFirstItem - var ajax_optionDiv; - var ajax_optionDiv_iframe; - - // set values - this.layoutCss='auto-complete.css'; - this.ajaxBox_offsetX = 0; - this.ajaxBox_offsetY = 0; - this.ajax_list_currentLetters = new Array(); - this.ajax_list_cachedLists = new Array(); - this.ajax_optionDiv = false; - this.ajax_list_MSIE = false; - if (navigator.userAgent.indexOf('MSIE')>=0 && navigator.userAgent.indexOf('Opera')<0) - this.ajax_list_MSIE=true; - this.ajax_list_activeItem; - this.ajax_list_objects = new Array(); - this.ajax_list_activeInput = false; - this.ajax_list_activeItem; - this.ajax_list_optionDivFirstItem = false; - this.ajax_optionDiv = false; - this.ajax_optionDiv_iframe = false; - - var ajax_list_MSIE = false; - if(navigator.userAgent.indexOf('MSIE')>=0 && navigator.userAgent.indexOf('Opera')<0) ajax_list_MSIE=true; - - this.minimumLettersBeforeLookup = 1; - - // check modules - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); - // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - // load object to variableStorage - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length;; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; - document.body.setAttribute("objectIndex",this.objectIndex); // set attribute to body for keyNavigation - - DHTMLSuite.commonObj.loadCSS(this.layoutCss); // load css - -} - -DHTMLSuite.autoComplete.prototype={ - - // {{{ add(inputObjId,externalFile) - /** - * add auto complete functionality for input object - * - * @param Number inputObjId - input object id - * @param String - cgi url - * - * @public - */ - add:function(inputObjId,externalFile){ - var refObject = DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]; - eval("document.getElementById('"+inputObjId+"').onkeyup = function(e) { refObject.__showOptions(e,'"+ inputObjId +"','"+ externalFile +"') };"); - DHTMLSuite.commonObj.__addEventEl(document.getElementById(inputObjId)); - } - // }}} - , - // {{{ setLayoutCss(newCssFileName) - /** - * Set new CSS file name - * - * @param String newCssFileName-name of new css file. Should be called before any tooltips are displayed on the screen. - * - *@public - */ - setLayoutCss:function(newCssFileName){ - this.layoutCss=newCssFileName; - } - // }}} - , - // {{{ __showOptions(inputObj,externalFile,e) - /** - * show Options - * - * @param Object inputObj - input object - * @param String externalFile - cgi url - * @param Object e - error handling - * - *@private - */ - __showOptions:function(e, inputObjId,externalFile){ - var inputObj = document.getElementById(inputObjId); // input object - var ind = this.objectIndex; // class object index - - if(document.all)e = event; - if(e.keyCode==13 || e.keyCode==9)return; - if(this.ajax_list_currentLetters[inputObj.name]==inputObj.value) return; - if(!this.ajax_list_cachedLists[inputObj.id]) this.ajax_list_cachedLists[inputObj.id] = new Array(); - - this.ajax_list_currentLetters[inputObj.name] = inputObj.value; - if(!this.ajax_optionDiv){ - this.ajax_optionDiv = document.createElement('DIV'); - this.ajax_optionDiv.id = 'ajax_listOfOptions'; - document.body.appendChild(this.ajax_optionDiv); - - if(this.ajax_list_MSIE){ - this.ajax_optionDiv_iframe = document.createElement('IFRAME'); - this.ajax_optionDiv_iframe.border='0'; - this.ajax_optionDiv_iframe.style.width = this.ajax_optionDiv.clientWidth + 'px'; - this.ajax_optionDiv_iframe.style.height = this.ajax_optionDiv.clientHeight + 'px'; - this.ajax_optionDiv_iframe.id = 'ajax_listOfOptions_iframe'; - - document.body.appendChild(this.ajax_optionDiv_iframe); - } - - var allInputs = document.getElementsByTagName('INPUT'); - for(var no=0;no this.ajax_optionDiv.offsetHeight){ - this.ajax_optionDiv.scrollTop = this.ajax_list_activeItem.offsetTop - this.ajax_optionDiv.offsetHeight + this.ajax_list_activeItem.offsetHeight + 2 ; - } - if(this.ajax_list_activeItem.offsetTop < this.ajax_optionDiv.scrollTop){ - this.ajax_optionDiv.scrollTop = 0; - } - } - } - // }}} - , - // {{{ __ajaxOptionResize(inputObj) - /** - * rollover effect for options - * - * @param object item - - * @param bollean fromKeyBoard - - * - *@private - */ - __ajaxOptionResize:function(inputObj){ - this.ajax_optionDiv.style.top = (this.__ajaxGetTopPos(inputObj) + inputObj.offsetHeight + this.ajaxBox_offsetY) + 'px'; - this.ajax_optionDiv.style.left = (this.__ajaxGetLeftPos(inputObj) + this.ajaxBox_offsetX) + 'px'; - if(this.ajax_optionDiv_iframe){ - this.ajax_optionDiv_iframe.style.left = this.ajax_optionDiv.style.left; - this.ajax_optionDiv_iframe.style.top = this.ajax_optionDiv.style.top; - } - - } - // }}} - , - // {{{ __ajaxGetTopPos(inputObj) - /** - * find top position of div including options - * - * @param object inputObj - input object for using auto complete - * - *@private - */ - __ajaxGetTopPos:function(inputObj){ - var returnValue = inputObj.offsetTop; - while((inputObj = inputObj.offsetParent) != null){ - returnValue += inputObj.offsetTop; - } - return returnValue; - } - // }}} - , - // {{{ __ajaxGetLeftPos(inputObj) - /** - * find left position of div including options - * - * @param object inputObj - input object for using auto complete - * - *@private - */ - __ajaxGetLeftPos:function(inputObj){ - var returnValue = inputObj.offsetLeft; - while((inputObj = inputObj.offsetParent) != null)returnValue += inputObj.offsetLeft; - - return returnValue; - } - // }}} - , - // {{{ __ajaxOptionListShowContent(ajaxIndex,inputObj) - /** - * call build options function and show content - * - * @param number ajaxIndex - * @param object inputObj - input object - * - *@private - */ - __ajaxOptionListShowContent:function(ajaxIndex,inputObj){ - var letters = inputObj.value; - var content = this.ajax_list_objects[ajaxIndex].response; - var elements = content.split('|'); - this.ajax_list_cachedLists[inputObj.id][letters.toLowerCase()] = elements; - this.__ajaxOptionListBuildList(letters,inputObj.id); - - } - // }}} - , - // {{{ __ajaxOptionListBuildList(letters,inputObjId) - /** - * build options list - * - * @param string letters : input value - * @param string inputObjId - * - *@private - */ - __ajaxOptionListBuildList:function(letters,inputObjId){ - var ind = this.objectIndex; - - //alert(inputObjId); - - this.ajax_optionDiv.innerHTML = ''; - this.ajax_list_activeItem = false; - if(this.ajax_list_cachedLists[inputObjId][letters.toLowerCase()].length<=1){ - this.__ajaxOptionsHide(); - return; - } - - this.ajax_list_optionDivFirstItem = false; - var optionsAdded = false; - for(var no=0;noDemo) -* @version 0.1 -* @author Alf Magne Kalleland & Batur Orkun -* (www.dhtmlgoodies.com) -*/ - -DHTMLSuite.chainedSelect=function(){ - - var targetSels; - var sourceSels; - var urls; - - var waitMessage; - var layoutCss; - var objectIndex; - - this.targetSels = new Array(); - this.sourceSels = new Array(); - this.urls = new Array(); - - try{ - if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); - // This line starts all the init methods - }catch(e){ - alert('You need to include the dhtmlSuite-common.js file'); - } - - this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length;; - DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; -} - -DHTMLSuite.chainedSelect.prototype={ - // {{{ init() - /** - * Initializes the script - * - * - * @public - */ - init:function() - { - var ind = this.objectIndex; - for(index=0; index1)targetObj.options[targetObj.options.length] = new Option(option_array[0].trim(), option_array[1].trim()); - } - - } -} +/*[FILE_START:dhtmlSuite-common.js] */ +/************************************************************************************************************ + @fileoverview + DHTML Suite for Applications. + Copyright (C) 2006 Alf Magne Kalleland(post@dhtmlgoodies.com)
    +
    + This library is free software; you can redistribute it and/or
    + modify it under the terms of the GNU Lesser General Public
    + License as published by the Free Software Foundation; either
    + version 2.1 of the License, or (at your option) any later version.
    +
    + This library 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
    + Lesser General Public License for more details.
    +
    + You should have received a copy of the GNU Lesser General Public
    + License along with this library; if not, write to the Free Software
    + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    +
    +
    + www.dhtmlgoodies.com
    + Alf Magne Kalleland
    + +************************************************************************************************************/ + +/** + * + * @package DHTMLSuite for applications + * @copyright Copyright © 2006, www.dhtmlgoodies.com + * @author Alf Magne Kalleland + */ + +/****** +Some prototypes: +**/ + + // Creating a trim method +if(!String.trim)String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); }; +var DHTMLSuite_funcs = new Object(); +if(!window.DHTML_SUITE_THEME)var DHTML_SUITE_THEME = 'blue'; +if(!window.DHTML_SUITE_THEME_FOLDER)var DHTML_SUITE_THEME_FOLDER = '../themes/'; +if(!window.DHTML_SUITE_JS_FOLDER)var DHTML_SUITE_JS_FOLDER = '../js/separateFiles/'; + +/************************************************************************************************************ +* +* Global variables +* +************************************************************************************************************/ + + // {{{ DHTMLSuite.createStandardObjects() +/** + * Create objects used by all scripts + * + * @public + */ + +var DHTMLSuite = new Object(); + +var standardObjectsCreated = false; // The classes below will check this variable, if it is false, default help objects will be created +DHTMLSuite.eventEls = new Array(); // Array of elements that has been assigned to an event handler. + +var widgetDep = new Object(); + // Widget dependencies +widgetDep['formValidator'] = ['dhtmlSuite-formUtil.js']; // Form validator widget +widgetDep['paneSplitter'] = ['dhtmlSuite-paneSplitter.js','dhtmlSuite-paneSplitterModel.js','dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['menuBar'] = ['dhtmlSuite-menuBar.js','dhtmlSuite-menuItem.js','dhtmlSuite-menuModel.js']; +widgetDep['windowWidget'] = ['dhtmlSuite-windowWidget.js','dhtmlSuite-resize.js','dhtmlSuite-dragDropSimple.js','ajax.js','dhtmlSuite-dynamicContent.js']; +widgetDep['colorWidget'] = ['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js']; +widgetDep['colorSlider'] = ['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js','dhtmlSuite-slider.js']; +widgetDep['colorPalette'] = ['dhtmlSuite-colorWidgets.js','dhtmlSuite-colorUtil.js']; +widgetDep['calendar'] = ['dhtmlSuite-calendar.js','dhtmlSuite-dragDropSimple.js']; +widgetDep['dragDropTree'] = ['dhtmlSuite-dragDropTree.js']; +widgetDep['slider'] = ['dhtmlSuite-slider.js']; +widgetDep['dragDrop'] = ['dhtmlSuite-dragDrop.js']; +widgetDep['imageEnlarger'] = ['dhtmlSuite-imageEnlarger.js','dhtmlSuite-dragDropSimple.js']; +widgetDep['imageSelection'] = ['dhtmlSuite-imageSelection.js']; +widgetDep['floatingGallery'] = ['dhtmlSuite-floatingGallery.js','dhtmlSuite-mediaModel.js']; +widgetDep['contextMenu'] = ['dhtmlSuite-contextMenu.js','dhtmlSuite-menuBar.js','dhtmlSuite-menuItem.js','dhtmlSuite-menuModel.js']; +widgetDep['dynamicContent'] = ['dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['textEdit'] = ['dhtmlSuite-textEdit.js','dhtmlSuite-textEditModel.js','dhtmlSuite-listModel.js']; +widgetDep['listModel'] = ['dhtmlSuite-listModel.js']; +widgetDep['resize'] = ['dhtmlSuite-resize.js']; +widgetDep['dragDropSimple'] = ['dhtmlSuite-dragDropSimple.js']; +widgetDep['dynamicTooltip'] = ['dhtmlSuite-dynamicTooltip.js','dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['modalMessage'] = ['dhtmlSuite-modalMessage.js','dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['tableWidget'] = ['dhtmlSuite-tableWidget.js','ajax.js']; +widgetDep['progressBar'] = ['dhtmlSuite-progressBar.js']; +widgetDep['tabView'] = ['dhtmlSuite-tabView.js','dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['infoPanel'] = ['dhtmlSuite-infoPanel.js','dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['form'] = ['dhtmlSuite-formUtil.js','dhtmlSuite-dynamicContent.js','ajax.js']; +widgetDep['autoComplete']=['dhtmlSuite-autoComplete.js','ajax.js']; +widgetDep['chainedSelect']=['dhtmlSuite-chainedSelect.js','ajax.js']; + +var depCache = new Object(); + +DHTMLSuite.include = function(widget){ + if(!widgetDep[widget]){ + alert('Cannot find the files for widget ' + widget + '. Please verify that the name is correct'); + return; + } + var files = widgetDep[widget]; + for(var no=0;no'); + document.write(''); + depCache[files[no]] = true; + } + } +} + +DHTMLSuite.discardElement = function(element) { + element = DHTMLSuite.commonObj.getEl(element); + var gBin = document.getElementById('IELeakGBin'); + if (!gBin) { + gBin = document.createElement('DIV'); + gBin.id = 'IELeakGBin'; + gBin.style.display = 'none'; + document.body.appendChild(gBin); + } + // move the element to the garbage bin + gBin.appendChild(element); + gBin.innerHTML = ''; +} + +DHTMLSuite.createStandardObjects = function(){ + DHTMLSuite.clientInfoObj = new DHTMLSuite.clientInfo(); // Create browser info object + DHTMLSuite.clientInfoObj.init(); + if(!DHTMLSuite.configObj){ // If this object isn't allready created, create it. + DHTMLSuite.configObj = new DHTMLSuite.config(); // Create configuration object. + DHTMLSuite.configObj.init(); + } + DHTMLSuite.commonObj = new DHTMLSuite.common(); // Create configuration object. + DHTMLSuite.variableStorage = new DHTMLSuite.globalVariableStorage();; // Create configuration object. + DHTMLSuite.commonObj.init(); + DHTMLSuite.domQueryObj = new DHTMLSuite.domQuery(); + + DHTMLSuite.commonObj.addEvent(window,'unload',function(){ DHTMLSuite.commonObj.__clearMemoryGarbage(); }); + + standardObjectsCreated = true; +} + +/************************************************************************************************************ +* Configuration class used by most of the scripts +* +* Created: August, 19th, 2006 +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class Store global variables/configurations used by the classes below. Example: If you want to +* change the path to the images used by the scripts, change it here. An object of this +* class will always be available to the other classes. The name of this object is +* "DHTMLSuite.configObj".

    +* +* If you want to create an object of this class manually, remember to name it "DHTMLSuite.configObj" +* This object should then be created before any other objects. This is nescessary if you want +* the other objects to use the values you have put into the object.
    +* @version 1.0 +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ +DHTMLSuite.config = function(){ + var imagePath; // Path to images used by the classes. + var cssPath; // Path to CSS files used by the DHTML suite. + + var defaultCssPath; + var defaultImagePath; +} + +DHTMLSuite.config.prototype = { + // {{{ init() + /** + * Initializes the config object - the config class is used to store global properties used by almost all widgets + * + * @public + */ + init : function(){ + this.imagePath = DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/images/'; // Path to images + this.cssPath = DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/css/'; // Path to images + + this.defaultCssPath = this.cssPath; + this.defaultImagePath = this.imagePath; + + } + // }}} + , + // {{{ setCssPath() + /** + * This method will save a new CSS path, i.e. where the css files of the dhtml suite are located(the folder). + * This method is rarely used. Default value is the variable DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/css', + * which means that the css path is set dynamically based on which theme you choose. + * + * @param string newCssPath = New path to css files(folder - remember to have a slash(/) at the end) + * @public + */ + + setCssPath : function(newCssPath){ + this.cssPath = newCssPath; + } + // }}} + , + // {{{ resetCssPath() + /** + * @deprecated + * Resets css path back to default value which is ../css_dhtmlsuite/ + * This method is deprecated. + * + * @public + */ + resetCssPath : function(){ + this.cssPath = this.defaultCssPath; + } + // }}} + , + // {{{ resetImagePath() + /** + * @deprecated + * + * Resets css path back to default path which is DHTML_SUITE_THEME_FOLDER + DHTML_SUITE_THEME + '/css' + * This method is deprecated. + * @public + */ + resetImagePath : function(){ + this.imagePath = this.defaultImagePath; + } + // }}} + , + // {{{ setImagePath() + /** + * This method will save a new image file path, i.e. where the image files used by the dhtml suite ar located + * + * @param string newImagePath = New path to image files (remember to have a slash(/) at the end) + * @public + */ + setImagePath : function(newImagePath){ + this.imagePath = newImagePath; + } + // }}} +} + +DHTMLSuite.globalVariableStorage = function(){ + var menuBar_highlightedItems; // Array of highlighted menu bar items + this.menuBar_highlightedItems = new Array(); + + var arrayDSObjects; // Array of objects of class menuItem. + var arrayOfDhtmlSuiteObjects; + this.arrayDSObjects = new Array(); + this.arrayOfDhtmlSuiteObjects = this.arrayDSObjects; + var ajaxObjects; + this.ajaxObjects = new Array(); +} + +DHTMLSuite.globalVariableStorage.prototype = { + +} + +/************************************************************************************************************ +* A class with general methods used by most of the scripts +* +* Created: August, 19th, 2006 +* Purpose of class: A class containing common method used by one or more of the gui classes below, +* example: loadCSS. +* An object("DHTMLSuite.commonObj") of this class will always be available to the other classes. +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class A class containing common method used by one or more of the gui classes below, example: loadCSS. An object("DHTMLSuite.commonObj") of this class will always be available to the other classes. +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.common = function(){ + var loadedCSSFiles; // Array of loaded CSS files. Prevent same CSS file from being loaded twice. + var cssCacheStatus; // Css cache status + var eventEls; + var isOkToSelect; // Boolean variable indicating if it's ok to make text selections + + this.okToSelect = true; + this.cssCacheStatus = true; // Caching of css files = on(Default) + this.eventEls = new Array(); +} + +DHTMLSuite.common.prototype = { + + // {{{ init() + /** + * This method initializes the DHTMLSuite_common object. + * This class contains a lot of useful methods used by most widgets. + * + * @public + */ + init : function(){ + this.loadedCSSFiles = new Array(); + } + // }}} + , + // {{{ loadCSS() + /** + * This method loads a CSS file(Cascading Style Sheet) dynamically - i.e. an alternative to tag in the document. + * + * @param string cssFile = Name of css file. It will be loaded from the path specified in the DHTMLSuite.common object + * @param Boolean prefixConfigPath = Use config path as prefix. + * @public + */ + loadCSS : function(cssFile,prefixConfigPath){ + if(!prefixConfigPath && prefixConfigPath!==false)prefixConfigPath=true; + if(!this.loadedCSSFiles[cssFile]){ + this.loadedCSSFiles[cssFile] = true; + var lt = document.createElement('LINK'); + if(!this.cssCacheStatus){ + if(cssFile.indexOf('?')>=0)cssFile = cssFile + '&'; else cssFile = cssFile + '?'; + cssFile = cssFile + 'rand='+ Math.random(); // To prevent caching + } + if(prefixConfigPath){ + lt.href = DHTMLSuite.configObj.cssPath + cssFile; + }else{ + lt.href = cssFile; + } + lt.rel = 'stylesheet'; + lt.media = 'screen'; + lt.type = 'text/css'; + document.getElementsByTagName('HEAD')[0].appendChild(lt); + } + } + // }}} + , + // {{{ __setTextSelOk() + /** + * Is it ok to make text selections ? + * + * @param Boolean okToSelect + * @private + */ + __setTextSelOk : function(okToSelect){ + this.okToSelect = okToSelect; + } + // }}} + , + // {{{ __setTextSelOk() + /** + * Returns true if it's ok to make text selections, false otherwise. + * + * @return Boolean okToSelect + * @private + */ + __isTextSelOk : function(){ + return this.okToSelect; + } + // }}} + , + // {{{ setCssCacheStatus() + /** + * Specify if css files should be cached or not. + * + * @param Boolean cssCacheStatus = true = cache on, false = cache off + * + * @public + */ + setCssCacheStatus : function(cssCacheStatus){ + this.cssCacheStatus = cssCacheStatus; + } + // }}} + , + // {{{ getEl() + /** + * Return a reference to an object + * + * @param Object elRef = Id, name or direct reference to element + * @return Object HTMLElement - direct reference to element + * @public + */ + getEl : function(elRef){ + if(typeof elRef=='string'){ + if(document.getElementById(elRef))return document.getElementById(elRef); + if(document.forms[elRef])return document.forms[elRef]; + if(document[elRef])return document[elRef]; + if(window[elRef])return window[elRef]; + } + return elRef; // Return original ref. + + } + // }}} + , + // {{{ isArray() + /** + * Return true if element is an array + * + * @param Object el = Reference to HTML element + * @public + */ + isArray : function(el){ + if(el.constructor.toString().indexOf("Array") != -1)return true; + return false; + } + // }}} + , + // {{{ getStyle() + /** + * Return specific style attribute for an element + * + * @param Object el = Reference to HTML element + * @param String property = Css property + * @public + */ + getStyle : function(el,property){ + el = this.getEl(el); + if (document.defaultView && document.defaultView.getComputedStyle) { + var retVal = null; + var comp = document.defaultView.getComputedStyle(el, ''); + if (comp){ + retVal = comp[property]; + } + return el.style[property] || retVal; + } + if (document.documentElement.currentStyle && DHTMLSuite.clientInfoObj.isMSIE){ + var retVal = null; + if(el.currentStyle)value = el.currentStyle[property]; + return (el.style[property] || retVal); + } + return el.style[property]; + } + // }}} + , + // {{{ getLeftPos() + /** + * This method will return the left coordinate(pixel) of an HTML element + * + * @param Object el = Reference to HTML element + * @public + */ + getLeftPos : function(el){ + /* + if(el.getBoundingClientRect){ // IE + var box = el.getBoundingClientRect(); + return (box.left/1 + Math.max(document.body.scrollLeft,document.documentElement.scrollLeft)); + } + */ + if(document.getBoxObjectFor){ + if(el.tagName!='INPUT' && el.tagName!='SELECT' && el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).x + } + var returnValue = el.offsetLeft; + while((el = el.offsetParent) != null){ + if(el.tagName!='HTML'){ + returnValue += el.offsetLeft; + if(document.all)returnValue+=el.clientLeft; + } + } + return returnValue; + } + // }}} + , + // {{{ getTopPos() + /** + * This method will return the top coordinate(pixel) of an HTML element/tag + * + * @param Object el = Reference to HTML element + * @public + */ + getTopPos : function(el){ + /* + if(el.getBoundingClientRect){ // IE + var box = el.getBoundingClientRect(); + return (box.top/1 + Math.max(document.body.scrollTop,document.documentElement.scrollTop)); + } + */ + if(document.getBoxObjectFor){ + if(el.tagName!='INPUT' && el.tagName!='SELECT' && el.tagName!='TEXTAREA')return document.getBoxObjectFor(el).y + } + + var returnValue = el.offsetTop; + while((el = el.offsetParent) != null){ + if(el.tagName!='HTML'){ + returnValue += (el.offsetTop - el.scrollTop); + if(document.all)returnValue+=el.clientTop; + } + } + return returnValue; + } + // }}} + , + // {{{ getCookie() + /** + * + * These cookie functions are downloaded from + * http://www.mach5.com/support/analyzer/manual/html/General/CookiesJavaScript.htm + * + * This function returns the value of a cookie + * + * @param String name = Name of cookie + * @param Object inputObj = Reference to HTML element + * @public + */ + getCookie : function(name) { + var start = document.cookie.indexOf(name+"="); + var len = start+name.length+1; + if ((!start) && (name != document.cookie.substring(0,name.length))) return null; + if (start == -1) return null; + var end = document.cookie.indexOf(";",len); + if (end == -1) end = document.cookie.length; + return unescape(document.cookie.substring(len,end)); + } + // }}} + , + // {{{ setCookie() + /** + * + * These cookie functions are downloaded from + * http://www.mach5.com/support/analyzer/manual/html/General/CookiesJavaScript.htm + * + * This function creates a cookie. (This method has been slighhtly modified) + * + * @param String name = Name of cookie + * @param String value = Value of cookie + * @param Int expires = Timestamp - days + * @param String path = Path for cookie (Usually left empty) + * @param String domain = Cookie domain + * @param Boolean secure = Secure cookie(SSL) + * + * @public + */ + setCookie : function(name,value,expires,path,domain,secure) { + expires = expires * 60*60*24*1000; + var today = new Date(); + var expires_date = new Date( today.getTime() + (expires) ); + var cookieString = name + "=" +escape(value) + + ( (expires) ? ";expires=" + expires_date.toGMTString() : "") + + ( (path) ? ";path=" + path : "") + + ( (domain) ? ";domain=" + domain : "") + + ( (secure) ? ";secure" : ""); + document.cookie = cookieString; + } + // }}} + , + // {{{ deleteCookie() + /** + * + * This function deletes a cookie. (This method has been slighhtly modified) + * + * @param String name = Name of cookie + * @param String path = Path for cookie (Usually left empty) + * @param String domain = Cookie domain + * + * @public + */ + deleteCookie : function( name, path, domain ) + { + if ( this.getCookie( name ) ) document.cookie = name + "=" + + ( ( path ) ? ";path=" + path : "") + + ( ( domain ) ? ";domain=" + domain : "" ) + + ";expires=Thu, 01-Jan-1970 00:00:01 GMT"; + } + // }}} + , + // {{{ cancelEvent() + /** + * + * This function only returns false. It is used to cancel selections and drag + * + * + * @public + */ + + cancelEvent : function(){ + return false; + } + // }}} + , + // {{{ addEvent() + /** + * + * This function adds an event listener to an element on the page. + * + * @param Object whichObject = Reference to HTML element(Which object to assigne the event) + * @param String eventType = Which type of event, example "mousemove" or "mouseup" (NOT "onmousemove") + * @param functionName = Name of function to execute. + * + * @public + */ + addEvent : function( obj, type, fn,suffix ) { + if(!suffix)suffix = ''; + if ( obj.attachEvent ) { + if ( typeof DHTMLSuite_funcs[type+fn+suffix] != 'function') { + DHTMLSuite_funcs[type+fn+suffix] = function() { + fn.apply(window.event.srcElement); + }; + obj.attachEvent('on'+type, DHTMLSuite_funcs[type+fn+suffix] ); + } + obj = null; + } else { + obj.addEventListener( type, fn, false ); + } + this.__addEventEl(obj); + } + + // }}} + , + // {{{ removeEvent() + /** + * + * This function removes an event listener from an element on the page. + * + * @param Object whichObject = Reference to HTML element(Which object to assigne the event) + * @param String eventType = Which type of event, example "mousemove" or "mouseup" + * @param functionName = Name of function to execute. + * + * @public + */ + removeEvent : function(obj,type,fn,suffix){ + if ( obj.detachEvent ) { + obj.detachEvent( 'on'+type, DHTMLSuite_funcs[type+fn+suffix] ); + DHTMLSuite_funcs[type+fn+suffix] = null; + obj = null; + } else { + obj.removeEventListener( type, fn, false ); + } + } + // }}} + , + // {{{ __clearMemoryGarbage() + /** + * + * This function is used for Internet Explorer in order to clear memory when the page unloads. + * + * + * @private + */ + __clearMemoryGarbage : function(){ + /* Example of event which causes memory leakage in IE + DHTMLSuite.commonObj.addEvent(expandRef,"click",function(){ window.refToMyMenuBar[index].__changeMenuBarState(this); }) + We got a circular reference. + */ + if(!DHTMLSuite.clientInfoObj.isMSIE)return; + + for(var no=0;no'; + img.outerHTML = html; + + } + , + // {{{ __evaluateJs() + /** + * Evaluate Javascript in the inserted content + * + * @private + */ + __evaluateJs : function(obj){ + obj = this.getEl(obj); + var scriptTags = obj.getElementsByTagName('SCRIPT'); + var string = ''; + var jsCode = ''; + for(var no=0;no tag. + * + * @private + */ + __installScript : function ( script ){ + try{ + if (!script) + return; + if (window.execScript){ + window.execScript(script) + }else if(window.jQuery && jQuery.browser.safari){ // safari detection in jQuery + window.setTimeout(script,0); + }else{ + window.setTimeout( script, 0 ); + } + }catch(e){ + + } + } + // }}} + , + // {{{ __evaluateCss() + /** + * Evaluates css + * + * @private + */ + __evaluateCss : function(obj){ + obj = this.getEl(obj); + var cssTags = obj.getElementsByTagName('STYLE'); + var head = document.getElementsByTagName('HEAD')[0]; + for(var no=0;no=0)?true:false; + this.isFirefox = (this.browser.toLowerCase().indexOf('firefox')>=0)?true:false; + this.isMSIE = (this.browser.toLowerCase().indexOf('msie')>=0)?true:false; + this.isOldMSIE = (this.browser.toLowerCase().match(/msie\s[0-6]/gi))?true:false; + this.isSafari = (this.browser.toLowerCase().indexOf('safari')>=0)?true:false; + this.navigatorVersion = navigator.appVersion.replace(/.*?MSIE\s(\d\.\d).*/g,'$1')/1; + this.isOldMSIE = (this.isMSIE&&this.navigatorVersion<7)?true:false; + } + // }}} + , + // {{{ getBrowserWidth() + /** + * + * + * This method returns the width of the browser window(i.e. inner width) + * + * + * @public + */ + getBrowserWidth : function(){ + if(self.innerWidth)return self.innerWidth; + return document.documentElement.offsetWidth; + } + // }}} + , + // {{{ getBrowserHeight() + /** + * + * + * This method returns the height of the browser window(i.e. inner height) + * + * + * @public + */ + getBrowserHeight : function(){ + if(self.innerHeight)return self.innerHeight; + return document.documentElement.offsetHeight; + } +} + +/************************************************************************************************************ +* DOM query class +* +* Created: August, 31th, 2006 +* +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class Purpose of class: Gives you a set of methods for querying elements on a webpage. When an object +* of this class has been created, the method will also be available via the document object. +* Example: var elements = document.getElementsByClassName('myClass'); +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.domQuery = function(){ + // Make methods of this class a member of the document object. + document.getElementsByClassName = this.getElementsByClassName; + document.getElementsByAttribute = this.getElementsByAttribute; +} + +DHTMLSuite.domQuery.prototype = { +} + +/*[FILE_START:dhtmlSuite-tableWidget.js] */ +/************************************************************************************************************ +* Table widget page handler class +* +* Created: December, 15th, 2006 +* Purpose of class: Displays paginating below a server sorted table +* +* CSS used: +* +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class Purpose of class: Make HTML tables sortable

    +*/ +DHTMLSuite.tableWidgetPageHandler=function(){ + var tableRef; + // Reference to object of class DHTMLSuite.tableWidget + var targetRef; + // Where to insert the pagination. + + var txtPrevious; + // Label-"Previous" + var txtNext; + // Label-"Next" + var txtFirst; + // Label-"First" + var txtLast; + // Label-"last" + + var txtResultPrefix; + // Prefix:result-default="Result: " + var txtResultTo; + // Text label Result: 1 "to" 10 of 51-default value="to" + var txtResultOf; + // Text label Result: 1 to 10 "of" 51-default value="of" + + var totalNumberOfRows; + // Total number of rows in dataset + var rowsPerPage; + // Number of rows per page. + + var layoutCSS; + // Name of CSS file for the table widget. + var activePageNumber; + // Active page number + var mainDivEl; + // Reference to main div for the page handler + var resultDivElement; + // Reference to div element which is parent for the result + var pageListDivEl; + // Reference to div element which is parent to pages [1],[2],[3]...[Next] + + var objectIndex; + // Index of this widget in the arrayDSObjects array + + var linkPagePrefix; + // Text in front of each page link + var linkPageSuffix; + // Text behind each page link + + var maximumNumberOfPageLinks; + // Maximum number of page links. + var callbackOnAfterNavigate; + // Callback function-executed when someone navigates to a different page + this.txtPrevious='Previous'; + // Default label + this.txtNext='Next'; + // Default label + this.txtResultPrefix='Result: '; + // Default label + this.txtResultTo='to'; + // Default label + this.txtResultOf='of'; + // Default label + this.txtFirst='First'; + this.txtLast='Last'; + + this.tableRef=false; + this.targetRef=false; + this.totalNumberOfRows=false; + this.activePageNumber=0; + this.layoutCSS='table-widget-page-handler.css'; + + this.linkPagePrefix=''; + this.linkPageSuffix=''; + this.maximumNumberOfPageLinks=false; + this.callbackOnAfterNavigate=false; + + this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this; + +} + +DHTMLSuite.tableWidgetPageHandler.prototype={ + + // {{{ setTableRef() + /** + * Connect to a tableWidget object. + * + * @param Object tableRef=An object of class DHTMLSuite.tableWidget. It makes it possible for the tableWidget and this object to communicate. + * + *@public + */ + setTableRef:function(tableRef){ + this.tableRef=tableRef; + this.tableRef.setPageHandler(this); + } + + // }}} + , + + // {{{ setTargetId() + /** + * Where do you want to insert the navigation links for the table + * + * @param String idOfHTMLElement=Id of HTML Element on your page. + * + *@public + */ + setTargetId:function(idOfHTMLElement){ + if(!document.getElementById(idOfHTMLElement)){ + alert('ERROR IN tableWidgetPageHandler.setTargetId:\nElement with id '+idOfHTMLElement+' does not exists'); + return; + } + this.targetRef=document.getElementById(idOfHTMLElement); + } + + // }}} + , + + // {{{ setTxtPrevious() + /** + * Set text label (previous page link) + * + * @param String newText=Text previous page link + * + *@public + */ + setTxtPrevious:function(newText){ + this.txtPrevious=newText; + } + + // }}} + , + + // {{{ setLinkPagePrefix() + /** + * Set text/characters in front of each page link, example "[" to get page number in brackets + * + * @param String linkPagePrefix=Character(s)in front of page links + * + *@public + */ + setLinkPagePrefix:function(linkPagePrefix){ + this.linkPagePrefix=linkPagePrefix; + } + + // }}} + , + + // {{{ setLinkPageSuffix() + /** + * Set text/characters in front of each page link, example "[" to get page number in brackets + * + * @param String linkPageSuffix=Character(s)in front of page links + * + *@public + */ + setLinkPageSuffix:function(linkPageSuffix){ + this.linkPageSuffix=linkPageSuffix; + } + + // }}} + , + + // {{{ setTxtNext() + /** + * Set text label (next page link) + * + * @param String newText=Text next page link + * + *@public + */ + setTxtNext:function(newText){ + this.txtNext=newText; + } + + // }}} + , + + // {{{ setTxtResultOf() + /** + * Set text label ("of"-result) + * + * @param String txtResultOf=Result of search, the "of" label ( Result: 1 to 10 "of" 51 ) + * + *@public + */ + setTxtResultOf:function(txtResultOf){ + this.txtResultOf=txtResultOf; + } + + // }}} + , + + // {{{ setTxtResultTo() + /** + * Set text label ("to"-result) + * + * @param String txtResultTo=Result of search, the "to" label ( Result: 1 "to" 10 of 51 ) + * + *@public + */ + setTxtResultTo:function(txtResultTo){ + this.txtResultTo=txtResultTo; + } + + // }}} + , + + // {{{ setTxtResultPrefix() + /** + * Set text label (prefix-result) + * + * @param String txtResultPrefix=Text next page link + * + *@public + */ + setTxtResultPrefix:function(txtResultPrefix){ + this.txtResultPrefix=txtResultPrefix; + } + + // }}} + , + + // {{{ setTxtFirstPage() + /** + * Set text label ("Last" page) + * + * @param String txtFirst=Label of link to "First" page ( default="First" ).This option is only used when you are limiting the number of pages shown. + * + *@public + */ + setTxtFirstPage:function(txtFirst){ + this.txtFirst=txtFirst; + } + + // }}} + , + + // {{{ setTxtLastPage() + /** + * Set text label ("First" page) + * + * @param String txtLast=Label of link to "Last" page ( default="Last" ).This option is only used when you are limiting the number of pages shown. + * + *@public + */ + setTxtLastPage:function(txtLast){ + this.txtLast=txtLast; + } + + // }}} + , + + // {{{ setTotalNumberOfRows() + /** + * Specify total number of rows in the entire dataset + * + * @param Integer totalNumberOfRows=Total number of rows in the entire dataset. + * + *@public + */ + setTotalNumberOfRows:function(totalNumberOfRows){ + this.totalNumberOfRows=totalNumberOfRows; + } + + // }}} + , + + // {{{ setCallbackOnAfterNavigate() + /** + *Specify call back function to execute after page navigatoin + * + *@param String callbackOnAfterNavigate-name of javascript function. + * + *@public + */ + setCallbackOnAfterNavigate:function(callbackOnAfterNavigate){ + this.callbackOnAfterNavigate=callbackOnAfterNavigate; + } + + // }}} + , + + // {{{ setLayoutCss() + /** + *set new CSS file + * + *@param String cssFileName-name of new css file(example: drag-drop.css). Has to be set before init is called. + * + *@public + */ + setLayoutCss:function(layoutCSS){ + this.layoutCSS=layoutCSS; + } + + // }}} + , + + // {{{ setMaximumNumberOfPageLinks() + /** + *Set maximum number of page links displayed below the table, i.e. if you have 50 pages, you can limit number of page links to 10 by sending 10 to this method. + * + *@param Integer maximumNumberOfPageLinks-(0 or false means=no limitation) + * + *@public + */ + setMaximumNumberOfPageLinks:function(maximumNumberOfPageLinks){ + this.maximumNumberOfPageLinks=maximumNumberOfPageLinks; + } + + // }}} + , + + // {{{ init() + /** + *Initializes the script widget. Set methods should be called before your call this method. + * + * + *@public + */ + init:function(){ + this.rowsPerPage=this.tableRef.getServersideSortNumberOfRows(); + DHTMLSuite.commonObj.loadCSS(this.layoutCSS); + this.__createMainDivEls(); + this.setHTMLOfResultList(); + this.__createPageLinks(); + this.goToPage(1); + } + + // }}} + , + + // {{{ __createMainDivEls() + /** + *Create main div elements for the page handler + * + * + *@private + */ + __createMainDivEls:function(){ + if(!this.targetRef){ + alert('Error creating table widget page handler. Remember to specify targetRef'); + return; + } + this.mainDivEl=document.createElement('DIV'); + this.mainDivEl.className='DHTMLSuite_tableWidgetPageHandler_mainDiv'; + this.targetRef.appendChild(this.mainDivEl); + + this.resultDivElement=document.createElement('DIV'); + this.resultDivElement.className='DHTMLSuite_tableWidgetPageHandler_result'; + this.mainDivEl.appendChild(this.resultDivElement); + + this.pageListDivEl=document.createElement('DIV'); + this.pageListDivEl.className='DHTMLSuite_tableWidgetPageHandler_pageList'; + this.mainDivEl.appendChild(this.pageListDivEl); + } + + , + + // {{{ setHTMLOfResultList() + /** + * + * Create result list div + * + * + * + *@public + */ + setHTMLOfResultList:function(){ + this.resultDivElement.innerHTML=''; + var html=this.txtResultPrefix+(((this.activePageNumber-1)* this.rowsPerPage)+1)+' '+this.txtResultTo+' '+Math.min(this.totalNumberOfRows,(this.activePageNumber*this.rowsPerPage))+' '+this.txtResultOf+' '+this.totalNumberOfRows; + this.resultDivElement.innerHTML=html; + } + + // }}} + , + + // {{{ __createPageLinks() + /** + * + * Create page links + * + *@private + */ + __createPageLinks:function(){ + var ind=this.objectIndex; + this.pageListDivEl.innerHTML=''; + // Clearing the div element if it allready got content. + var numberOfPages=Math.ceil(this.totalNumberOfRows/this.rowsPerPage); + + /* link to first page */ + if(this.maximumNumberOfPageLinks&&this.maximumNumberOfPageLinks=0){ + var pageNo=src.id.replace(/[^0-9]/gi,'')/1; + this.activePageNumber=pageNo; + + } + if(src.id=='next'){ + // next link clicked + this.activePageNumber++; + if(this.activePageNumber>numberOfPages)this.activePageNumber=numberOfPages; + } + if(src.id=='previous'){ + this.activePageNumber--; + if(this.activePageNumber<1)this.activePageNumber=1; + } + + if(this.activePageNumber!=initActivePageNumber){ + this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage); + this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate); + this.setHTMLOfResultList(); + this.__createPageLinks(); + } + return false; + + } + + // }}} + , + + // {{{ __resetActivePageNumber() + /** + * + * Reset active page number-called from the tableWidget + * + * + *@private + */ + __resetActivePageNumber:function(){ + this.activePageNumber=1; + this.setHTMLOfResultList(); + this.__createPageLinks(); + } + + // }}} + , + + // {{{ goToPage() + /** + * + * Go to a page + * @param Integer pageNumber + * + * + *@public + */ + goToPage:function(pageNo){ + var initActivePageNumber=this.activePageNumber; + this.activePageNumber=pageNo; + if(this.activePageNumber!=initActivePageNumber){ + this.tableRef.serversideSortCurrentStartIndex=((this.activePageNumber-1)*this.rowsPerPage); + this.tableRef.__getItemsFromServer(this.callbackOnAfterNavigate); + this.setHTMLOfResultList(); + this.__createPageLinks(); + } + } +} + +/************************************************************************************************************ +* Table widget class +* +* Created: August, 18th, 2006 +* Purpose of class: Make HTML tables sortable +* Apply application look to the table +* Create one object for each HTML table. +* +* CSS used: table-widget.css +* images used: arrow_up.gif +* arrow_down.gif +* +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class Purpose of class: Make HTML tables sortable

    +* Apply application look to the table
    +* Create one object for each HTML table.
    +*
    +* Remember to have both <THEAD> and <TBODY> in your table. +*
    +* <DIV>
    +* <table>
    +* <thead>
    +* <tr>
    +* <td>Header cell</td>
    +* <td>Header cell</td>
    +* </tr>
    +* </thead>
    +* <tbody>
    +* <tr>
    +* <td>Table data</td>
    +* <td>Table data</td>
    +* </tr>
    +* <tr>
    +* <td>Table data</td>
    +* <td>Table data</td>
    +* </tr>
    +* </tbody>
    +* </table>
    +* </div>
    +*

    +* Also remember: If you put a table inside a non-displayed element, example an inactive tab(the tabView script), remember to create +* and initialize the table objects before you create the tab objects. In some browsers, that's nescessary in order for the table to +* display properly.
    +* (demo 1) +* +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.tableWidget=function(){ + var tableWidget_okToSort; + // Variable indicating if it's ok to sort. This variable is "false" when sorting is in progress + var activeColumn; + // Reference to active column, i.e. column currently beeing sorted + var idOfTable; + // Id of table, i.e. the tag + var tableObj; + // Reference to
    tag. + var widthOfTable; + // Width of table (Used in the CSS) + var heightOfTable; + // Height of table (Used in the CSS) + var columnSortArray; + // Array of how table columns should be sorted + var layoutCSS; + // Name of CSS file for the table widget. + var noCssLayout; + // true or false, indicating if the table should have layout or not, if not, it would be a plain sortable table. + var serversideSort; + // true or false, true if the widget is sorted on the server. + var serversideSortAscending; + var tableCurrentlySortedBy; + var serversideSortFileName; + // Name of file on server to send request to when table data should be sorted + var serversideSortNumberOfRows; + // Number of rows to receive from the server + var serversideSortCurrentStartIndex; + // Index of first row in the dataset, i.e. if you move to next page, this value will be incremented + var serversideSortExtraSearchCriterias; + // Extra param to send to the server, example: &firstname=Alf&lastname=Kalleland + var pageHandler; + // Object of class DHTMLSuite.tableWidgetPageHandler + var rowClickCallBackFunction; + // Row click call back function. + var objectIndex; + // Index of this object in the DHTMLSuite.variableStorage.arrayDSObjects array + + this.serversideSort=false; + // Default value for serversideSort(items are sorted in the client) + this.serversideSortAscending=true; + // Current sort ( ascending or descending) + this.tableCurrentlySortedBy=false; + this.serversideSortFileName=false; + this.serversideSortCurrentStartIndex=0; + this.serversideSortExtraSearchCriterias=''; + this.rowClickCallBackFunction=false; + this.setRowDblClickCallBackFunction=false; + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); + // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + + this.objectIndex=DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]=this; +} + +DHTMLSuite.tableWidget.prototype={ + /** + * Public method used to initialize the table widget script. First use the set methods to configure the script, then + * call the init method. + **/ + + // {{{ init() + /** + * + * Initializes the table widget object + * + * + *@public + */ + init:function(){ + this.tableWidget_okToSort=true; + this.activeColumn=false; + if(!this.layoutCSS)this.layoutCSS='table-widget.css'; + DHTMLSuite.commonObj.loadCSS(this.layoutCSS); + this.__initTableWidget(); + } + + // }}} + , + + // {{{ setLayoutCss() + /** + * + * This function updates name of CSS file. This method should be called before init(). + * + *@param String newCssFile=(File name of CSS file, not path) + * + *@public + */ + setLayoutCss:function(newCssFile){ + this.layoutCSS=newCssFile; + } + + // }}} + , + + // + // {{{ setRowClickCallBackFunction() + /** + * + * This method specifies call back function to be called when a row is clicked. A reference to that row is sent as argument to this function + * + *@param String rowClickCallBackFunction=(Row click-call back function) + * + *@public + */ + setRowClickCallBack:function(rowClickCallBackFunction){ + this.rowClickCallBackFunction=rowClickCallBackFunction; + } + + // }}} + , + + // + // {{{ setRowDblClickCallBackFunction() + /** + * + * This method specifies call back function to be called when a row is double clicked. A reference to that row is sent as argument to this function + * + *@param String setRowDblClickCallBackFunction=(Row click-call back function) + * + *@public + */ + setRowDblClickCallBack:function(setRowDblClickCallBackFunction){ + this.setRowDblClickCallBackFunction=setRowDblClickCallBackFunction; + } + + // }}} + , + + // {{{ setServerSideSort() + /** + * + * This method is used to specify if you want to your tables to be sorted on the server or not. + * + *@param Boolean serversideSort=Sort items on the server? (true=yes, false=no). + * + *@public + */ + setServerSideSort:function(serversideSort){ + this.serversideSort=serversideSort; + } + + // }}} + , + + // {{{ setServersideSearchCriterias() + /** + * + * This method is used to add extra params to the search url sent to the server. + * + *@param String serversideSortExtraSearchCriterias=String added to the url, example: "&firstname=John&lastname=Doe". This can be used in the sql query on the server. + * + *@public + */ + setServersideSearchCriterias:function(serversideSortExtraSearchCriterias){ + this.serversideSortExtraSearchCriterias=serversideSortExtraSearchCriterias; + } + + // }}} + , + + // {{{ getServersideSortNumberOfRows() + /** + * + * Return numer of rows per page. + * + *@return Integer serversideSort=Number of rows + * + *@public + */ + getServersideSortNumberOfRows:function(serversideSort){ + return this.serversideSortNumberOfRows; + } + + // }}} + , + + // {{{ setServersideSortNumberOfRows() + /** + * + * Specify how many records to receive from the server ( server side sort ) + * + *@param Integer serversideSortNumberOfRows=Number of rows + * + *@public + */ + setServersideSortNumberOfRows:function(serversideSortNumberOfRows){ + this.serversideSortNumberOfRows=serversideSortNumberOfRows; + } + + // }}} + , + + // {{{ setServersideSortFileName() + /** + * + * This method is used to specify which file to send the ajax request to when data should be sorted. (i.e. sort items on server instead of client). + * + *@param String serversideSortFileName=Path to file on server. This file will receive the request, parse it and send back new table data. + * + *@public + */ + setServersideSortFileName:function(serversideSortFileName){ + this.serversideSortFileName=serversideSortFileName; + } + + // }}} + , + /* Start public methods */ + + // {{{ setNoCssLayout() + /** + * + * No CSS layout + * + * + *@public + */ + setNoCssLayout:function(){ + this.noCssLayout=true; + } + + // }}} + , + + // {{{ sortTableByColumn() + /** + * + * This method sorts a table by a column + * You can call this method after the call to init if you want to sort the table by a column when the table is beeing displayed. + * + *@param Int columnIndex=Column to sort by (0=first column) + *@param String howToSort How to sort the table ("ascending" or "descending" + * + *@public + */ + sortTableByColumn:function(columnIndex,howToSort){ + if(!howToSort)howToSort='ascending'; + var tableObj=document.getElementById(this.idOfTable); + var firstRow=tableObj.rows[0]; + var tds=firstRow.cells; + if(tds[columnIndex]&&this.columnSortArray[columnIndex]){ + this.__sortTable(tds[columnIndex],howToSort); + } + } + + // }}} + , + + // {{{ setTableId() + /** + * + * Set id of table, i.e. the id of the
    tag you want to apply the table widget to + * + *@param String idOfTable=Id of table + * + *@public + */ + setTableId:function(idOfTable){ + this.idOfTable=idOfTable; + try{ + this.tableObj=document.getElementById(idOfTable); + }catch(e){ + + } + } + + // }}} + , + + // {{{ setTableWidth() + /** + * + * Set width of table + * + *@param Mixed width=(string if percentage width, integer if numeric/pixel width) + * + *@public + */ + setTableWidth:function(width){ + this.widthOfTable=width; + } + + // }}} + , + + // {{{ setTableHeight() + /** + * + * Set height of table + * + *@param Mixed height=(string if percentage height, integer if numeric/pixel height) + * + *@public + */ + setTableHeight:function(height){ + this.heightOfTable=height; + } + + // }}} + , + + // {{{ setColumnSort() + /** + * + * How to sort the table + * + *@param Array columnSortArray=How to sort the columns in the table(An array of the items 'N','S' or false) + * + *@public + */ + setColumnSort:function(columnSortArray){ + this.columnSortArray=columnSortArray; + } + + // }}} + , + + // {{{ addNewRow() + /** + * Adds a new row to the table dynamically + * + *@param Array cellContent=Array of strings-cell content + * + *@public + */ + addNewRow:function(cellContent){ + var tObj=document.getElementById(this.idOfTable); + var tb=tObj.getElementsByTagName('TBODY')[0]; + + var row=tb.insertRow(-1); + for(var no=0;no + var tbody=tableObj.getElementsByTagName('TBODY')[0]; + // Reference to the + var thead=tableObj.getElementsByTagName('THEAD')[0]; + // Reference to the + + var bodyRows=tbody.rows; + // Reference to all the inside the tag + var headerRows=thead.rows; + // Reference to all inside + + cellIndexSubtract=1; + // Firefox have a small cell at the right of each row which means that the new column should not be the last one, but second to last. + if(DHTMLSuite.clientInfoObj.isMSIE)cellIndexSubtract=0; + // Browser does not have this cell at the right + + // Add new header cell + var headerCell=headerRows[0].insertCell(headerRows[0].cells.length-cellIndexSubtract); + if(!this.noCssLayout)headerCell.className='DHTMLSuite_tableWidget_headerCell'; + headerCell.onselectstart=function(){ return false; }; + DHTMLSuite.commonObj.__addEventEl(headerCell); + headerCell.innerHTML=headerText; + if(sortMethod){ + this.__parseHeaderCell(headerCell); + }else{ + headerCell.style.cursor='default'; + } + + // Setting width of header cells. The last cell shouldn't have any right border + headerRows[0].cells[headerRows[0].cells.length-1].style.borderRightWidth='0px'; + headerRows[0].cells[headerRows[0].cells.length-2].style.borderRightWidth='1px'; + + // Add rows to the table + for(var no=0;no + * + *@private + */ + __parseHeaderCell:function(cellRef){ + if(!this.noCssLayout){ + cellRef.onmouseover=this.__highlightTableHeader; + cellRef.onmouseout= this.__removeHighlightEffectFromTableHeader; + cellRef.onmousedown=this.__mousedownOnTableHeader; + cellRef.onmouseup=this.__highlightTableHeader; + }else{ + cellRef.style.cursor='pointer'; + // No CSS layout -> just set cursor to pointer/hand. + } + + var refToThis=this; + // It doesn't work with "this" on the line below, so we create a variable refering to "this". + cellRef.onclick=function(){ refToThis.__sortTable(this); }; + DHTMLSuite.commonObj.__addEventEl(cellRef); + + var img=document.createElement('IMG'); + img.src=DHTMLSuite.configObj.imagePath+'table-widget/arrow_up.gif'; + cellRef.appendChild(img); + img.style.visibility='hidden'; + } + + // }}} + , + + // {{{ __parseDataRows() + /** + * Parses rows in a table, i.e. add events and align cells. + * + *@param Object parentObj=Reference to
    + * + *@private + */ + __parseDataRows:function(parentObj){ + var ind=this.objectIndex; + + // Loop through rows and assign mouseover and mouse out events+right align numeric cells. + for(var no=1;no=0){ + obj.style.width='100%'; + obj.parentNode.style.width=this.widthOfTable; + }else{ + obj.style.width=this.widthOfTable+'px'; + obj.parentNode.style.width=this.widthOfTable+'px'; + } + if(this.heightOfTable.indexOf('%')>=0){ + obj.parentNode.style.height=this.heightOfTable; + }else{ + obj.parentNode.style.height=this.heightOfTable+'px'; + } + } + if(!DHTMLSuite.clientInfoObj.isMSIE){ + this.__addEndCol(obj); + }else{ + obj.style.cssText='width:expression(this.parentNode.clientWidth)'; + } + + obj.cellSpacing=0; + obj.cellPadding=0; + if(!this.noCssLayout)obj.className='DHTMLSuite_tableWidget'; + var tHead=obj.getElementsByTagName('THEAD')[0]; + var cells=tHead.getElementsByTagName('TD'); + + var tBody=obj.getElementsByTagName('TBODY')[0]; + tBody.className='DHTMLSuite_scrollingContent'; + + for(var no=0;no=0){ + obj.parentNode.style.overflow='auto'; + } + } + } + this.__parseDataRows(obj); + var ind=this.objectIndex; + } + + // }}} + , + + // {{{ __addEndCol() + /** + * Adds a small empty cell at the right of the header row. This is done in order to make the table look pretty when the scrollbar appears. + * + *@param Object obj=Reference to
    + * + *@private + */ + __addEndCol:function(obj){ + var rows=obj.getElementsByTagName('TR'); + for(var no=0;no'; + cell.style.width='13px'; + cell.width='13'; + cell.style.overflow='hidden'; + } + + } + + // }}} + , + + // {{{ __highlightTableHeader() + /** + * Mouse over event: Highlights header cell on mouse over, i.e. applies an orange line at the top. + * + * + *@private + */ + __highlightTableHeader:function(){ + + // Here, "this" is a reference to the HTML tag triggering this event and not the table widget object + this.className='DHTMLSuite_tableWigdet_headerCellOver'; + if(document.all){ + // I.E fix for "jumping" headings + var divObj=this.parentNode.parentNode.parentNode.parentNode; + this.parentNode.style.top=divObj.scrollTop+'px'; + } + } + + // }}} + , + + // {{{ __removeHighlightEffectFromTableHeader() + /** + * Mouse out event: Remove the orange line at the top of header cells when the mouse moves away from the cell. + * + * + *@private + */ + __removeHighlightEffectFromTableHeader:function(){ + this.className='DHTMLSuite_tableWidget_headerCell'; + } + + // }}} + , + + // {{{ __mousedownOnTableHeader() + /** + * Mouse down event header cells. It changes the color of the header from light gray to dark gray. + * + *@private + */ + __mousedownOnTableHeader:function(){ + this.className='DHTMLSuite_tableWigdet_headerCellDown'; + if(document.all){ + // I.E fix for "jumping" headings + var divObj=this.parentNode.parentNode.parentNode.parentNode; + this.parentNode.style.top=divObj.scrollTop+'px'; + } + } + + // }}} + , + + // {{{ __sortNumeric() + /** + * Sort the table numerically + * ps! If you know that your tables always contains valid numbers(i.e. digits or decimal numbers like 7 and 7.5), + * then you can remove everything except return a/1-b/1; from this function. By removing these lines, the sort + * process be faster. + * + *@param String a=first number to compare + *@param String b=second number to compare + * + *@private + */ + __sortNumeric:function(a,b){ + + // changing commas(,)to periods(.) + a=a.replace(/,/,'.'); + b=b.replace(/,/,'.'); + + // Remove non digit characters-example changing "DHTML12.5" to "12.5" + a=a.replace(/[^\d\.\/]/g,''); + b=b.replace(/[^\d\.\/]/g,''); + + // Dealing with fractions(example: changing 4/5 to 0.8) + if(a.indexOf('/')>=0)a=eval(a); + if(b.indexOf('/')>=0)b=eval(b); + return a/1-b/1; + } + + // }}} + , + + // {{{ __sortString() + /** + * Sort the table letterically + * + *@param String a=first number to compare + *@param String b=second number to compare + * + *@private + */ + __sortString:function(a, b){ + if ( a.toUpperCase()< b.toUpperCase())return -1; + if ( a.toUpperCase()> b.toUpperCase())return 1; + return 0; + } + + // }}} + , + + // {{{ __parseDataContentFromServer() + /** + *This method parses data content from server and calls the __fillDataRow method with parsed data as argument. + * + * + *@private + */ + __parseDataContentFromServer:function(ajaxIndex){ + var content=DHTMLSuite.variableStorage.ajaxObjects[ajaxIndex].response; + if(content.indexOf('|||')==-1&&content.indexOf('###')==-1){ + alert('Error in data from server\n'+content); + return; + } + this.__clearDataRows(); + // Clear existing data + var rows=content.split('|||'); + // Create an array of each row + for(var no=0;no1)this.__fillDataRow(items); + } + this.__parseDataRows(this.tableObj); + } + + // }}} + , + + // {{{ __clearDataRows() + /** + *This method clear all data from the table(except header cells). + * + * + *@private + */ + __clearDataRows:function(){ + if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable); + while(this.tableObj.rows.length>1){ + DHTMLSuite.discardElement(this.tableObj.rows[this.tableObj.rows.length-1]); + } + } + + // }} + , + + // {{{ __fillDataRow() + /** + *Adds a new row of data to the table. + * + *@param Array data=Array of data + * + *@private + */ + __fillDataRow:function(data){ + if(!this.tableObj)this.tableObj=document.getElementById(this.idOfTable); + var tbody=this.tableObj.getElementsByTagName('TBODY')[0]; + var row=tbody.insertRow(-1); + for(var no=0;no 0 ) + sembol = '&'; + // batur :: end + var url=this.serversideSortFileName + sembol + 'sortBy='+this.tableCurrentlySortedBy+'&numberOfRows='+this.serversideSortNumberOfRows+'&sortAscending='+this.serversideSortAscending+'&startIndex='+this.serversideSortCurrentStartIndex+this.serversideSortExtraSearchCriterias; + var index=DHTMLSuite.variableStorage.ajaxObjects.length; + try{ + DHTMLSuite.variableStorage.ajaxObjects[index]=new sack(); + }catch(e){ + // Unable to create ajax object-send alert message and return from sort method. + alert('Unable to create ajax object. Please make sure that the sack js file is included on your page(js/ajax.js)'); + return; + } + DHTMLSuite.variableStorage.ajaxObjects[index].requestFile=url; + // Specifying which file to get + DHTMLSuite.variableStorage.ajaxObjects[index].onCompletion=function(){ DHTMLSuite.variableStorage.arrayDSObjects[objIndex].__parseDataContentFromServer(index);eval(callbackFunction)}; + // Specify function that will be executed after file has been found + DHTMLSuite.variableStorage.ajaxObjects[index].runAJAX(); + // Execute AJAX function + } + + // }}} + , + + // {{{ __sortTable() + /** + *Sort table-This method is called when someone clicks on the header of one of the sortable columns + * + *@param Object obj=reference to header cell triggering the sortTable method + * + *@private + */ + __sortTable:function(obj,howToSort){ + + // "this" is a reference to the table widget obj + + // "obj" is a reference to the header cell triggering the sortTable method. + + // Server side sort ? + if(this.serversideSort){ + if(!this.serversideSortFileName){ + // Server side file name defined. + alert('No server side file defined. Use the setServersideSortFileName to specify where to send the ajax request'); + return; + } + var sortBy=obj.getAttribute('sortBy'); + if(!sortBy)sortBy=obj.sortBy; + if(!sortBy){ + alert('Sort is not defined. Remember to set a sortBy attribute on the header '; + $out .= $this->newline; + } + + // Is there a table heading to display? + if (count($this->heading) > 0) + { + $out .= $this->template['heading_row_start']; + $out .= $this->newline; + + foreach($this->heading as $heading) + { + $out .= $this->template['heading_cell_start']; + $out .= $heading; + $out .= $this->template['heading_cell_end']; + } + + $out .= $this->template['heading_row_end']; + $out .= $this->newline; + } + + // Build the table rows + if (count($this->rows) > 0) + { + $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) + { + $out .= $this->template['cell_'.$name.'start']; + + if ($cell === "") + { + $out .= $this->empty_cells; + } + else + { + $out .= $cell; + } + + $out .= $this->template['cell_'.$name.'end']; + } + + $out .= $this->template['row_'.$name.'end']; + $out .= $this->newline; + } + } + + $out .= $this->template['table_close']; + + 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 = $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[] = $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 ( ! is_array($row)) + { + $this->rows[] = $data; + break; + } + + // 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 = $row; + } + else + { + $this->rows[] = $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','heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', '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' => '
    tags'); + return; + } + if(sortBy==this.tableCurrentlySortedBy)this.serversideSortAscending=!this.serversideSortAscending;else this.serversideSortAscending=true; + if(howToSort)this.serversideSortAscending=(howToSort=='ascending'?true:false); + this.tableCurrentlySortedBy=sortBy; + this.serversideSortCurrentStartIndex =0; + this.__getItemsFromServer(); + + if(this.pageHandler)this.pageHandler.__resetActivePageNumber(); + this.__updateSortArrow(obj,this.serversideSortAscending?'ascending':'descending'); + + return; + } + + if(!this.tableWidget_okToSort)return; + this.tableWidget_okToSort=false; + /* Getting index of current column */ + var indexThis=0; + var tmpObj=obj; + while(tmpObj.previousSibling){ + tmpObj=tmpObj.previousSibling; + if(tmpObj.tagName=='TD')indexThis++; + } + if(obj.getAttribute('direction')||obj.direction){ + // Determine if we should sort ascending or descending + direction=obj.getAttribute('direction'); + if(navigator.userAgent.indexOf('Opera')>=0)direction=obj.direction; + if(direction=='ascending'||howToSort=='descending'){ + direction='descending'; + obj.setAttribute('direction','descending'); + obj.direction='descending'; + }else{ + direction='ascending'; + obj.setAttribute('direction','ascending'); + obj.direction='ascending'; + } + }else{ + // First call to the sort method + var curDir='ascending'; + // How to sort the table + if(howToSort)curDir=howToSort; + // Initial sort method sent as argument to this method, call it by this method. + direction=curDir; + obj.setAttribute('direction',curDir); + obj.direction=curDir; + } + + this.__updateSortArrow(obj,direction); + var tableObj=obj.parentNode.parentNode.parentNode; + var tBody=tableObj.getElementsByTagName('TBODY')[0]; + var widgetIndex=tableObj.id.replace(/[^\d]/g,''); + var sortMethod=this.columnSortArray[indexThis]; + // N=numeric, S=String + var cellArray=new Array(); + var cellObjArray=new Array(); + for(var no=1;no=0;no--){ + for(var no2=0;no2 +* The constructor takes an associative array as only argument. Possible keys in this array:
    +* cloneNode - Clone the node, i.e. make the clone dragable
    +* allowMoveX - Allow drag along the x-axis
    +* allowMoveY - Allow drag along the y-axis
    +* minX - Minimum x coordinate on screen
    +* minY - Minimum y coordinate on screen
    +* maxX - Maximum x coordinate on screen
    +* maxY - Maximum y coordinate on screen
    +* callbackOnBeforeDrag - Name of function to execute before drag starts - The event object will be sent to this function.
    +* callbackOnAfterDrag - Name of function to execute after drag - The event object will be sent to this function.
    +* callbackOnDuringDrag - Name of function to execute during drag - The event object will be sent to this function.
    +* elementReference -
    +* dragHandle -
    +*
    +*
    +* Demos: (demo 1, The window widget), +* @version 1.0 +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ +DHTMLSuite.dragDropSimple = function(propertyArray){ + var divElement; + var dragTimer; // -1 no drag, 0-4 = initializing , 5 = drag in process + var cloneNode; + this.cloneNode = true; + + var callbackOnAfterDrag; + var callbackOnBeforeDrag; + var callbackOnDuringDrag; + + var mouse_x; + var mouse_y; + var positionSet; + var dragHandle; // If a specific element is specified to be a drag handle. + + var allowMoveX; + var allowMoveY; + var maxY; + var minY; + var minX; + var maxX; + + var initialXPos; + var initialYPos; + + this.positionSet = false; + this.dragHandle = new Array(); + var initOffsetX; + var initOffsetY; + + this.allowMoveX = true; + this.allowMoveY = true; + this.maxY = false; + this.maxX = false; + this.minX = false; + this.minY = false; + + this.callbackOnAfterDrag = false; + this.callbackOnBeforeDrag = false; + + this.dragStatus = -1; + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + var objectIndex; + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + this.__setInitProps(propertyArray); + this.__init(); +} + +DHTMLSuite.dragDropSimple.prototype = { + // {{{ __init() + /** + * Initializes the script + * + * @private + */ + __setInitProps : function(props){ + if(props.cloneNode===false || props.cloneNode)this.cloneNode=props.cloneNode; + if(props.allowMoveX===false || props.allowMoveX)this.allowMoveX=props.allowMoveX; + if(props.allowMoveY===false || props.allowMoveY)this.allowMoveY=props.allowMoveY; + if(props.minY || props.minY===0)this.minY=props.minY; + if(props.maxY || props.maxY===0)this.maxY=props.maxY; + if(props.minX || props.minX===0)this.minX=props.minX; + if(props.maxX || props.maxX===0)this.maxX=props.maxX; + + if(!props.initOffsetX)props.initOffsetX = 0; + if(!props.initOffsetY)props.initOffsetY = 0; + this.initOffsetX = props.initOffsetX; + this.initOffsetY = props.initOffsetY; + if(props.callbackOnBeforeDrag)this.callbackOnBeforeDrag = props.callbackOnBeforeDrag; + if(props.callbackOnAfterDrag)this.callbackOnAfterDrag = props.callbackOnAfterDrag; + if(props.callbackOnDuringDrag)this.callbackOnDuringDrag = props.callbackOnDuringDrag; + props.elementReference = DHTMLSuite.commonObj.getEl(props.elementReference); + this.divElement = props.elementReference; + this.initialXPos = DHTMLSuite.commonObj.getLeftPos(this.divElement); + this.initialYPos = DHTMLSuite.commonObj.getTopPos(this.divElement); + if(props.dragHandle)this.dragHandle[this.dragHandle.length] = DHTMLSuite.commonObj.getEl(props.dragHandle) + } + // }}} + , + // {{{ __init() + /** + * Initializes the script + * + * @private + */ + __init : function(){ + var ind = this.objectIndex; + this.divElement.objectIndex = ind; + this.divElement.setAttribute('objectIndex',ind); + this.divElement.style.padding = '0px'; + if(this.allowMoveX){ + this.divElement.style.left = (DHTMLSuite.commonObj.getLeftPos(this.divElement) + this.initOffsetX) + 'px'; + } + if(this.allowMoveY){ + this.divElement.style.top = (DHTMLSuite.commonObj.getTopPos(this.divElement) + this.initOffsetY) + 'px'; + } + this.divElement.style.position = 'absolute'; + this.divElement.style.margin = '0px'; + + if(this.divElement.style.zIndex && this.divElement.style.zIndex/1>DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=this.divElement.style.zIndex/1; + DHTMLSuite_dragDropSimple_curZIndex = DHTMLSuite_dragDropSimple_curZIndex/1 + 1; + this.divElement.style.zIndex = DHTMLSuite_dragDropSimple_curZIndex; + + if(this.cloneNode){ + var copy = this.divElement.cloneNode(true); + this.divElement.parentNode.insertBefore(copy,this.divElement); + copy.style.visibility = 'hidden'; + document.body.appendChild(this.divElement); + } + DHTMLSuite.commonObj.addEvent(this.divElement,'mousedown',function(e){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__initDragProcess(e); },ind); + DHTMLSuite.commonObj.addEvent(document.documentElement,'mousemove',function(e){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__moveDragableElement(e); },ind); + DHTMLSuite.commonObj.addEvent(document.documentElement,'mouseup',function(e){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__stopDragProcess(e); },ind); + if(!document.documentElement.onselectstart)document.documentElement.onselectstart = function() { return DHTMLSuite.commonObj.__isTextSelOk(); }; + } + // }}} + , + // {{{ setCallbackOnAfterDrag() + /** + * Specify name of function to execute after drag is completed. + * + * @param String functionName - Name of function to execute + * + * @private + */ + setCallbackOnAfterDrag : function(functionName){ + this.callbackOnAfterDrag = functionName; + } + // }}} + , + // {{{ setCallbackOnBeforeDrag() + /** + * Specify name of function to execute before drag is executed. + * + * @param String functionName - Name of function to execute + * + * @private + */ + setCallbackOnBeforeDrag : function(functionName){ + this.callbackOnBeforeDrag = functionName; + } + // }}} + , + // {{{ addDragHandle() + /** + * Specify a drag handle + * + * @param Object HTML Element - element inside the dragable element specified to act as a drag handle. + * + * @private + */ + addDragHandle : function(dragHandle){ + this.dragHandle[this.dragHandle.length] = dragHandle; + } + // }}} + , + // {{{ __initDragProcess() + /** + * Initializes drag process + * + * @private + */ + __initDragProcess : function(e){ + if(document.all)e = event; + var ind = this.objectIndex; + DHTMLSuite_dragDropSimple_curObjIndex = ind; + var thisObject = DHTMLSuite.variableStorage.arrayDSObjects[ind]; + if(!DHTMLSuite.commonObj.isObjectClicked(thisObject.divElement,e))return; + if(thisObject.divElement.style.zIndex && thisObject.divElement.style.zIndex/1>DHTMLSuite_dragDropSimple_curZIndex)DHTMLSuite_dragDropSimple_curZIndex=thisObject.divElement.style.zIndex/1; + DHTMLSuite_dragDropSimple_curZIndex = DHTMLSuite_dragDropSimple_curZIndex/1 +1; + thisObject.divElement.style.zIndex = DHTMLSuite_dragDropSimple_curZIndex; + if(thisObject.callbackOnBeforeDrag){ + thisObject.__handleCallback('beforeDrag',e); + } + if(thisObject.dragHandle.length>0){ // Drag handle specified? + var objectFound; + for(var no=0;no=0 && this.dragTimer<5){ + this.dragTimer++; + setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].__waitBeforeDragProcessStarts()',5); + } + } + // }}} + , + // {{{ __moveDragableElement() + /** + * Move dragable element if drag is in process + * + * @param Event e - Event object - since this method is triggered by an event + * + * @private + */ + __moveDragableElement : function(e){ + if(document.all)e = event; + var ind = this.objectIndex; + var thisObj = DHTMLSuite.variableStorage.arrayDSObjects[ind]; + if(DHTMLSuite.clientInfoObj.isMSIE && e.button!=1)return thisObj.__stopDragProcess(); + if(thisObj.dragTimer==5){ + if(thisObj.allowMoveX){ + var leftPos = (e.clientX - this.mouse_x + this.el_x); + if(this.maxX!==false){ + if(leftPos + document.documentElement.scrollLeft>this.initialXPos+this.maxX){ + leftPos = this.initialXPos+this.maxX; + } + } + if(this.minX!==false){ + if(leftPos + document.documentElement.scrollLeftthis.initialYPos+this.maxY){ + topPos = this.initialYPos+this.maxY; + } + } + if(this.minY!==false){ + if(topPos DHTMLSuite_dragDropSimple_curZIndex){ + DHTMLSuite_dragDropSimple_curZIndex = zIndex/1+1; + } + } + +} + +/*[FILE_START:dhtmlSuite-dragDrop.js] */ +/************************************************************************************************************ +* Drag and drop class +* +* Created: August, 18th, 2006 +* +* Update log: +* +************************************************************************************************************/ +/** +* @constructor +* @class Purpose of class: A general drag and drop class. By creating objects of this class, you can make elements +* on your web page dragable and also assign actions to element when an item is dropped on it. +* A page should only have one object of this class.
    +*
    +* IMPORTANT when you use this class: Don't assign layout to the dragable element ids +* Assign it to classes or the tag instead. example: If you make
    +* dragable, don't assign css to #dragableBox1. Assign it to div or .aBox instead.
    +* (demo 1, demo 2), +* demo 3, demo 4 +* and demo 5) +* @version 1.0 +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.dragDrop = function(){ + var mouse_x; // mouse x position when drag is started + var mouse_y; // mouse y position when drag is started. + + var el_x; // x position of dragable element + var el_y; // y position of dragable element + + var dragDropTimer; // Timer - short delay from mouse down to drag init. + var numericIdToBeDragged; // numeric reference to element currently being dragged. + var dragObjCloneArray; // Array of cloned dragable elements. every + var dragDropSourcesArray; // Array of source elements, i.e. dragable elements. + var dragDropTargetArray; // Array of target elements, i.e. elements where items could be dropped. + var currentZIndex; // Current z index. incremented on each drag so that currently dragged element is always on top. + var okToStartDrag; // Variable which is true or false. It would be false for 1/100 seconds after a drag has been started. + // This is useful when you have nested dragable elements. It prevents the drag process from staring on + // parent element when you click on dragable sub element. + var moveBackBySliding; // Variable indicating if objects should slide into place moved back to their location without any slide animation. + var dragX_allowed; // Possible to drag this element along the x-axis? + var dragY_allowed; // Possible to drag this element along the y-axis? + + var currentEl_allowX; + var currentEl_allowY; + var drag_minX; + var drag_maxX; + var drag_minY; + var drag_maxY; + var dragInProgress; // Variable which is true when drag is in progress, false otherwise + + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + this.dragX_allowed = true; + this.dragY_allowed = true; + this.currentZIndex = 21000; + this.dragDropTimer = -1; + this.dragObjCloneArray = new Array(); + this.numericIdToBeDragged = false; + + this.okToStartDrag = true; + this.moveBackBySliding = true; + this.dragInProgress = false; + + var objectIndex; + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + +} + +DHTMLSuite.dragDrop.prototype = { + + // {{{ init() + /** + * Initialize the script + * This method should be called after you have added sources and destinations. + * + * @public + */ + init : function(){ + this.__initDragDropScript(); + } + // }}} + , + // {{{ addSource() + /** + * Add dragable element + * + * @param String sourceId = Id of source + * @param boolean slideBackAfterDrop = Slide the item back to it's original location after drop. + * @param boolean xAxis = Allowed to slide along the x-axis(default = true, i.e. if omitted). + * @param boolean yAxis = Allowed to slide along the y-axis(default = true, i.e. if omitted). + * @param String dragOnlyWithinElId = You will only allow this element to be dragged within the boundaries of the element with this id. + * + * @public + */ + addSource : function(sourceId,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId){ + if(!this.dragDropSourcesArray)this.dragDropSourcesArray = new Array(); + if(!document.getElementById(sourceId)){ + alert('The source element with id ' + sourceId + ' does not exists. Check your HTML code'); + return; + } + if(xAxis!==false)xAxis = true; + if(yAxis!==false)yAxis = true; + var obj = document.getElementById(sourceId); + this.dragDropSourcesArray[this.dragDropSourcesArray.length] = [obj,slideBackAfterDrop,xAxis,yAxis,dragOnlyWithinElId]; + obj.setAttribute('dragableElement',this.dragDropSourcesArray.length-1); + obj.dragableElement = this.dragDropSourcesArray.length-1; + + } + // }}} + , + // {{{ addTarget() + /** + * Add drop target + * + * @param String targetId = Id of drop target + * @param String functionToCallOnDrop = name of function to call on drop. + * Input to this the function specified in functionToCallOnDrop function would be + * id of dragged element + * id of the element the item was dropped on. + * mouse x coordinate when item was dropped + * mouse y coordinate when item was dropped + * + * @public + */ + addTarget : function(targetId,functionToCallOnDrop){ + if(!this.dragDropTargetArray)this.dragDropTargetArray = new Array(); + if(!document.getElementById(targetId))alert('The target element with id ' + targetId + ' does not exists. Check your HTML code'); + var obj = document.getElementById(targetId); + this.dragDropTargetArray[this.dragDropTargetArray.length] = [obj,functionToCallOnDrop]; + } + // }}} + , + // {{{ setSlide() + /** + * Activate or deactivate sliding animations. + * + * @param boolean isSlidingAnimationEnabled = Move element back to orig. location in a sliding animation + * + * @public + */ + setSlide : function(isSlidingAnimationEnabled){ + this.moveBackBySliding = isSlidingAnimationEnabled; + } + // }}} + , + /* Start private methods */ + + // {{{ __initDragDropScript() + /** + * Initialize drag drop script - this method is called by the init() method. + * + * @private + */ + __initDragDropScript : function(){ + var ind = this.objectIndex; + var refToThis = this; + var startIndex = Math.random() + ''; + startIndex = startIndex.replace('.','')/1; + + for(var no=0;no=0 && this.dragDropTimer<5){ + this.dragDropTimer = this.dragDropTimer + 1; + setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].__waitBeforeDragProcessStarts()',2); + return; + } + if(this.dragDropTimer>=5){ + if(this.dragObjCloneArray[this.numericIdToBeDragged].style.display=='none'){ + this.dragDropSourcesArray[this.numericIdToBeDragged][0].style.visibility = 'hidden'; + var ref = this.dragObjCloneArray[this.numericIdToBeDragged]; + ref.style.display = 'block'; + ref.style.visibility = 'visible'; + ref.style.top = DHTMLSuite.commonObj.getTopPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0]) + 'px'; + ref.style.left = DHTMLSuite.commonObj.getLeftPos(this.dragDropSourcesArray[this.numericIdToBeDragged][0]) + 'px'; + } + } + } + // }}} + , + // {{{ __moveDragableElement() + /** + * Move dragable element according to mouse position when drag is in process. + * + * @param Event e = Event object, used to get x and y coordinate of mouse pointer + * + * @private + */ + __moveDragableElement : function(e){ + var ind = this.objectIndex; + if(document.all)e = event; + if(this.dragDropTimer<5)return false; + if(this.dragInProgress)return false; + this.dragInProgress = true; + var dragObj = this.dragObjCloneArray[this.numericIdToBeDragged]; + + if(this.currentEl_allowX){ + + var leftPos = (e.clientX - this.mouse_x + this.el_x); + if(this.drag_maxX){ + var tmpMaxX = this.drag_maxX - dragObj.offsetWidth; + if(leftPos > tmpMaxX)leftPos = tmpMaxX + if(leftPos < this.drag_minX)leftPos = this.drag_minX; + } + dragObj.style.left = leftPos + 'px'; + + } + if(this.currentEl_allowY){ + var topPos = (e.clientY - this.mouse_y + this.el_y); + if(this.drag_maxY){ + var tmpMaxY = this.drag_maxY - dragObj.offsetHeight; + if(topPos > tmpMaxY)topPos = tmpMaxY; + if(topPos < this.drag_minY)topPos = this.drag_minY; + } + dragObj.style.top = topPos + 'px'; + } + this.dragInProgress = false; + return false; + } + // }}} + , + // {{{ __stopDragProcess() + /** + * Drag process stopped. + * + * @param Event e = Event object, used to get x and y coordinate of mouse pointer + * + * @private + */ + __stopDragProcess : function(e){ + if(this.dragDropTimer<5)return false; + if(document.all)e = event; + + // Dropped on which element + var dropDestination = DHTMLSuite.commonObj.getSrcElement(e); + + var leftPosMouse = e.clientX + Math.max(document.body.scrollLeft,document.documentElement.scrollLeft); + var topPosMouse = e.clientY + Math.max(document.body.scrollTop,document.documentElement.scrollTop); + + if(!this.dragDropTargetArray)this.dragDropTargetArray = new Array(); + // Loop through drop targets and check if the coordinate of the mouse is over it. If it is, call specified drop function. + for(var no=0;no leftPosEl && leftPosMouse < (leftPosEl + widthEl) && topPosMouse > topPosEl && topPosMouse < (topPosEl + heightEl)){ + if(this.dragDropTargetArray[no][1]){ + try{ + eval(this.dragDropTargetArray[no][1] + '("' + this.dragDropSourcesArray[this.numericIdToBeDragged][0].id + '","' + this.dragDropTargetArray[no][0].id + '",' + e.clientX + ',' + e.clientY + ')'); + }catch(e){ + alert('Unable to execute \n' + this.dragDropTargetArray[no][1] + '("' + this.dragDropSourcesArray[this.numericIdToBeDragged][0].id + '","' + this.dragDropTargetArray[no][0].id + '",' + e.clientX + ',' + e.clientY + ')'); + } + } + break; + } + } + if(this.dragDropSourcesArray[this.numericIdToBeDragged][1]){ + this.__slideElementBackIntoItsOriginalPosition(this.numericIdToBeDragged); + } + // Variable cleanup after drop + this.dragDropTimer = -1; + DHTMLSuite.commonObj.__setTextSelOk(true); + this.numericIdToBeDragged = false; + } + // }}} + , + // {{{ __slideElementBackIntoItsOriginalPosition() + /** + * Slide an item back to it's original position + * + * @param Integer numId = numeric index of currently dragged element + * + * @private + */ + __slideElementBackIntoItsOriginalPosition : function(numId){ + // Coordinates current element position + var currentX = this.dragObjCloneArray[numId].style.left.replace('px','')/1; + var currentY = this.dragObjCloneArray[numId].style.top.replace('px','')/1; + + var ref = this.dragDropSourcesArray[numId][0]; + // Coordinates - where it should slide to + var targetX = DHTMLSuite.commonObj.getLeftPos(ref); + var targetY = DHTMLSuite.commonObj.getTopPos(ref);; + + if(this.moveBackBySliding){ + // Call the step by step slide method + this.__processSlideByPixels(numId,currentX,currentY,targetX,targetY); + }else{ + this.dragObjCloneArray[numId].style.display='none'; + ref.style.visibility = 'visible'; + } + } + // }}} + , + // {{{ __processSlideByPixels() + /** + * Move the element step by step in this method + * + * @param Int numId = numeric index of currently dragged element + * @param Int currentX = Elements current X position + * @param Int currentY = Elements current Y position + * @param Int targetX = Destination X position, i.e. where the element should slide to + * @param Int targetY = Destination Y position, i.e. where the element should slide to + * + * @private + */ + __processSlideByPixels : function(numId,currentX,currentY,targetX,targetY){ + // Find slide x value + var slideX = Math.round(Math.abs(Math.max(currentX,targetX) - Math.min(currentX,targetX)) / 10); + // Find slide y value + var slideY = Math.round(Math.abs(Math.max(currentY,targetY) - Math.min(currentY,targetY)) / 10); + + if(slideY<3 && Math.abs(slideX)<10)slideY = 3; // 3 is minimum slide value + if(slideX<3 && Math.abs(slideY)<10)slideX = 3; // 3 is minimum slide value + + if(currentX > targetX) slideX*=-1; // If current x is larger than target x, make slide value negative
    + if(currentY > targetY) slideY*=-1; // If current y is larger than target x, make slide value negative + + // Update currentX and currentY + currentX = currentX + slideX; + currentY = currentY + slideY; + + // If currentX or currentY is close to targetX or targetY, make currentX equal to targetX(or currentY equal to targetY) + if(Math.max(currentX,targetX) - Math.min(currentX,targetX) < 4)currentX = targetX; + if(Math.max(currentY,targetY) - Math.min(currentY,targetY) < 4)currentY = targetY; + + // Update CSS position(left and top) + this.dragObjCloneArray[numId].style.left = currentX + 'px'; + this.dragObjCloneArray[numId].style.top = currentY + 'px'; + + // currentX different than targetX or currentY different than targetY, call this function in again in 5 milliseconds + if(currentX!=targetX || currentY != targetY){ + window.thisRef = this; // Reference to this dragdrop object + setTimeout('window.thisRef.__processSlideByPixels("' + numId + '",' + currentX + ',' + currentY + ',' + targetX + ',' + targetY + ')',5); + }else{ // Slide completed. Make absolute positioned element invisible and original element visible + this.dragObjCloneArray[numId].style.display='none'; + this.dragDropSourcesArray[numId][0].style.visibility = 'visible'; + } + } +} + +/*[FILE_START:dhtmlSuite-tabView.js] */ +/************************************************************************************************************ +* Tab view class +* +* Created: August, 21st, 2006 +* +* Update log: +* +************************************************************************************************************/ + +if(!window.DHTMLSuite)var DHTMLSuite=new Object();/************************************************************************************************************ +* Tab view class +* +* Created: August, 21st, 2006 +* +* Update log: +* +************************************************************************************************************/ + + +var refToTabViewObjects=new Array(); +// Reference to objects of this class. + +// We need this because the script doesn't allways know which object to use + +/** +* @constructor +* @class Purpose of class: Tab view class-transfors plain HTML into tabable layers.
    +* (See demo 1 and demo 2) +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.tabView=function(){ + var textPadding; + // Tab spacing + var strictDocType ; + // Using a strict document type, i.e. + + var DHTMLSuite_tabObj; + // Reference to div surrounding the tab set + var activeTabIndex; + // Currently displayed tab(index-0=first tab) + var initActiveTabIndex; + // Initially displayed tab(index-0=first tab) + var ajaxObjects; + // Reference to ajax objects + var tabView_countTabs; + var tabViewHeight; + var tabSetParentId; + // Id of div surrounding the tab set. + var tabTitles; + // Tab titles + var width; + // width of tab view + var height; + // height of tab view + var layoutCSS; + var outsideObjectRefIndex; + // Which index of refToTabViewObjects refers to this object. + var maxNumberOfTabs; + var dynamicContentObj; + var closeButtons; + var refActiveTabContent; + + var callbackOnTabSwitch; + + this.initActiveTabIndex=0; + this.callbackOnTabSwitch=''; + this.refActiveTabContent=''; + + // Default variable values + this.textPadding=3; + this.strictDocType=true; + this.ajaxObjects=new Array(); + this.tabTitles=new Array(); + this.layoutCSS='tab-view.css'; + this.maxNumberOfTabs=6; + this.dynamicContentObj=false; + this.closeButtons=new Array(); + this.width='100%'; + this.height='500'; + + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); + // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } +} + +DHTMLSuite.tabView.prototype={ + + // {{{ init() + /** + *Initialize the script + * + *@public + */ + init:function() + { + DHTMLSuite.commonObj.loadCSS(this.layoutCSS); + this.outsideObjectRefIndex=refToTabViewObjects.length; + refToTabViewObjects[this.outsideObjectRefIndex]=this; + try{ + this.dynamicContentObj=new DHTMLSuite.dynamicContent(); + }catch(e){ + alert('You need to include DHTMLSuite-dynamicContent.js'); + } + this.__initializeAndParseTabs(false,false); + + } + + // }}} + , + + // {{{ setCallbackOnTabSwitch() + /** + *Set callback on tab switch + * + *@param String callbackOnTabSwitch=Name of function to execute when the user switches to a different tab. + * + *@public + */ + setCallbackOnTabSwitch:function(callbackOnTabSwitch) + { + this.callbackOnTabSwitch=callbackOnTabSwitch; + } + + // }}} + , + + // {{{ getMaximumNumberOfTabs() + /** + *Return maximum number of tabs + * + *@return Int maximumNumberOfTabs=Maximum number of tabs + * + *@public + */ + getMaximumNumberOfTabs:function() + { + return this.maxNumberOfTabs; + } + + // }}} + , + + // {{{ setMaximumTabs() + /** + *Set maximum number of tabs + * + *@param Int maximumNumberOfTabs=Maximum number of tabs + * + *@public + */ + setMaximumTabs:function(maximumNumberOfTabs) + { + this.maxNumberOfTabs=maximumNumberOfTabs; + } + + // }}} + , + + // {{{ setParentId() + /** + *Set padding on tabs + * + *@param String idOfParentHTMLElement=id of parent div + * + *@public + */ + setParentId:function(idOfParentHTMLElement) + { + this.tabSetParentId=idOfParentHTMLElement; + this.DHTMLSuite_tabObj=document.getElementById(idOfParentHTMLElement); + } + + // }}} + , + + // {{{ setWidth() + /** + *Set width of tab view + * + *@param String Width of tab view + * + *@public + */ + setWidth:function(newWidth) + { + this.width=newWidth; + } + + // }}} + , + + // {{{ setHeight() + /** + *Set height of tab view on tabs + * + *@param String Height of tab view + * + *@public + */ + setHeight:function(newHeight) + { + this.height=newHeight; + } + + // }}} + , + + // {{{ setIndexActiveTab() + /** + *Set index of initially active tab + * + *@param Int indexOfNewActiveTab=Index of active tab(0=first tab) + * + *@public + */ + setIndexActiveTab:function(indexOfNewActiveTab) + { + this.initActiveTabIndex=indexOfNewActiveTab; + } + + + // }}} + , + + // {{{ setTabTitles() + /** + *Set title of tabs + * + *@param Array titleOfTabs=Title of tabs + * + *@public + */ + setTabTitles:function(titleOfTabs) + { + this.tabTitles=titleOfTabs; + } + + + // }}} + , + + // {{{ setCloseButtons() + /** + *Specify which tabs that should have close buttons + * + *@param Array closeButtons=Array of true or false + * + *@public + */ + setCloseButtons:function(closeButtons) + { + this.closeButtons=closeButtons; + } + + // }}} + , + + // {{{ getReferenceToDivElement() + /** + * + *Returns a reference to the div element of a tab. + * + *@param String tabTitle=Title of tab + *@return Object Element to HTML div element for this tab. + * + *@public + */ + getReferenceToDivElementByTitle:function(tabTitle) + { + var index=this.getTabIndexByTitle(tabLabel); + // Get index of tab + if(index!=-1){ + var obj=document.getElementById('tabView'+this.tabSetParentId+'_'+index); + return obj; + } + return false; + } + + // }}} + , + + // {{{ getReferenceToDivElementById() + /** + * + *Returns a reference to the div element of a tab. + * + *@param String idOfTab=id of tab + *@return Object Element to HTML div element for this tab. + * + *@public + */ + getReferenceToDivElementById:function(idOfTab) + { + var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); + + for(var no=0;no-1 + this.displayATab(tabTitle,index); + return false; + } + if(this.tabView_countTabs>=this.maxNumberOfTabs)return; + // Maximum number of tabs reached-return + var div=document.createElement('DIV'); + // Create new tab content div. + div.className='DHTMLSuite_aTab'; + // Assign new tab to CSS class DHTMLSuite_aTab + this.DHTMLSuite_tabObj.appendChild(div); + // Appending new tab content div to main tab view div + var tabId=this.__initializeAndParseTabs(true,tabTitle,closeButton); + // Call the init method in order to create tab header and tab images + if(tabContent)div.innerHTML=tabContent; + // Static tab content specified, put it into the new div + if(tabContentUrl){ + // Get content from external file + this.dynamicContentObj.loadContent('tabView'+parentId +'_'+tabId,tabContentUrl); + } + // update tabTitles -- batur + this.tabTitles[tabId] = tabTitle; + + return true; + } + + + // }}} + , + + // {{{ deleteTab() + /** + * + *Delete a tab + * + *@param String tabLabel=Label of tab to delete(Optional) + *@param Int tabIndex=Index of tab to delete(Optional) + * + *@public + */ + deleteTab:function(tabLabel,tabIndex) + { + if(tabLabel){ + // Delete tab by tab title + var index=this.getTabIndexByTitle(tabLabel); + // Get index of tab + if(index!=-1){ + // Tab exists if index<>-1 + this.deleteTab(false,index); + } + + }else if(tabIndex>=0){ + // Delete tab by tab index. + if(document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex)){ + var obj=document.getElementById('tabTab'+this.tabSetParentId+'_'+tabIndex); + var id=obj.parentNode.parentNode.id; + DHTMLSuite.discardElement(obj); + var obj2=document.getElementById('tabView'+this.tabSetParentId+'_'+tabIndex); + DHTMLSuite.discardElement(obj2); + this.__resetTabIds(this.tabSetParentId); + this.initActiveTabIndex=-1; + var newIndex=0; + if(refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex==tabIndex)refToTabViewObjects[this.outsideObjectRefIndex].activeTabIndex=-1; + this.__showTab(this.tabSetParentId,newIndex,this.outsideObjectRefIndex); + } + } + } + + // }}} + , + // {{{ addContentToTab() + /** + *Add content to a tab dynamically. + * + *@param String tabLabel=Label of tab to delete(Optional) + *@param String filePath=Path to file you want to show inside the tab. + * + *@public + */ + addContentToTab:function(tabLabel,filePath) + { + var index=this.getTabIndexByTitle(tabLabel); + // Get index of tab + if(index!=-1){ + // Tab found + this.dynamicContentObj.loadContent('tabView'+this.tabSetParentId+'_'+index,filePath); + } + } + + // }}} + , + + // {{{ displayATab() + /** + *Display a tab manually + * + *@param String tabTitle=Label of tab to show(Optional) + *@param Int tabIndex=Index of tab to show(Optional) + * + *@public + */ + + displayATab:function(tabLabel,tabIndex) + { + if(tabLabel){ + // Delete tab by tab title + var index=this.getTabIndexByTitle(tabLabel); + // Get index of tab + if(index!=-1){ + // Tab exists if index<>-1 + this.initActiveTabIndex=index; + }else return false; + + }else{ + this.initActiveTabIndex=tabIndex; + } + + this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex) + } + + // }}} + , + + // {{{ getTabIndex() + /** + *Return index of active tab + * + *@type Integer tabIndex=Index of active tab(0=first tab) + * + *@public + */ + getTabIndex:function() + { + var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); + var tabIndex=0; + for(var no=0;no=0){ + if(divs[no].className!='tabInactive')return tabIndex; + tabIndex++; + } + } + + //tabInactive + return tabIndex; + } + + // }}} + , + + + // {{{ __setPadding() + /** + *Set padding on tabs + * + *@private + */ + __setPadding:function(obj,padding){ + var span=obj.getElementsByTagName('SPAN')[0]; + span.style.paddingLeft=padding+'px'; + span.style.paddingRight=padding+'px'; + } + + // }}} + , + + // {{{ __showTab() + /** + *Set padding + * + *@param String parentId=id of parent div + *@param Int tabIndex=Index of tab to show + *@param Int objectIndex=Index of refToTabViewObjects, reference to the object of this class. + * + *@private + */ + __showTab:function(parentId,tabIndex,objectIndex) + { + var parentId_div=parentId+"_"; + if(!document.getElementById('tabView'+parentId_div+tabIndex)){ + return; + } + + if(refToTabViewObjects[objectIndex].activeTabIndex>=0){ + if(refToTabViewObjects[objectIndex].activeTabIndex==tabIndex){ + return; + } + var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex); + if(!obj){ + refToTabViewObjects[objectIndex].activeTabIndex=0; + var obj=document.getElementById('tabTab'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex); + } + obj.className='tabInactive'; + obj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')'; + var imgs=obj.getElementsByTagName('IMG'); + var img=imgs[imgs.length-1]; + img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif'; + document.getElementById('tabView'+parentId_div+refToTabViewObjects[objectIndex].activeTabIndex).style.display='none'; + } + + var thisObj=document.getElementById('tabTab'+ parentId_div +tabIndex); + + thisObj.className='tabActive'; + thisObj.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_active.gif'+'\')'; + var imgs=thisObj.getElementsByTagName('IMG'); + var img=imgs[imgs.length-1]; + img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_active.gif'; + + document.getElementById('tabView'+parentId_div+tabIndex).style.display='block'; + this.refActiveTabContent=document.getElementById('tabView'+parentId_div+tabIndex); + refToTabViewObjects[objectIndex].activeTabIndex=tabIndex; + + refToTabViewObjects[objectIndex].__handleCallback('tabSwitch'); + + var parentObj=thisObj.parentNode; + var aTab=parentObj.getElementsByTagName('DIV')[0]; + countObjects=0; + var startPos=2; + var previousObjectActive=false; + while(aTab){ + if(aTab.tagName=='DIV'){ + if(previousObjectActive){ + previousObjectActive=false; + startPos-=2; + } + if(aTab==thisObj){ + startPos-=2; + previousObjectActive=true; + refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding+1); + }else{ + refToTabViewObjects[objectIndex].__setPadding(aTab,refToTabViewObjects[objectIndex].textPadding); + } + + aTab.style.left=startPos+'px'; + countObjects++; + startPos+=2; + } + aTab=aTab.nextSibling; + } + + return; + } + + // }}} + , + + // {{{ __handleCallback() + /** + *Set padding + * + *@param String action=Which call back action + * + *@private + */ + __handleCallback:function(action) + { + var callbackString=''; + switch(action) + { + case "tabSwitch": + callbackString=this.callbackOnTabSwitch; + break; + } + + if(callbackString){ + callbackString=callbackString+'(this.refActiveTabContent)'; + eval(callbackString); + } + } + + // }}} + , + + // {{{ tabClick() + /** + *Set padding + * + *@param String parentId=id of parent div + *@param Int tabIndex=Index of tab to show + * + *@private + */ + __tabClick:function(inputObj,index) + { + var idArray=inputObj.id.split('_'); + var parentId=inputObj.getAttribute('parentRefId'); + if(!parentId)parentId=inputObj.parentRefId; + this.__showTab(parentId,idArray[idArray.length-1].replace(/[^0-9]/gi,''),index); + + } + + // }}} + , + + // {{{ rolloverTab() + /** + *Set padding + * + * + *@private + */ + __rolloverTab:function() + { + if(this.className.indexOf('tabInactive')>=0){ + this.className='inactiveTabOver'; + this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_over.gif'+'\')'; + var imgs=this.getElementsByTagName('IMG'); + var img=imgs[imgs.length-1]; + + img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_over.gif'; + } + + } + + // }}} + , + + // {{{ rolloutTab() + /** + * + * + *@private + */ + __rolloutTab:function() + { + if(this.className== 'inactiveTabOver'){ + this.className='tabInactive'; + this.style.backgroundImage='url(\''+DHTMLSuite.configObj.imagePath+'tab-view/tab_left_inactive.gif'+'\')'; + var imgs=this.getElementsByTagName('IMG'); + var img=imgs[imgs.length-1]; + img.src=DHTMLSuite.configObj.imagePath+'tab-view/tab_right_inactive.gif'; + } + } + + // }}} + , + + // {{{ __initializeAndParseTabs() + /** + * + *@param Int additionalTab=Additional tabs to the existing + *@param String nameOfAdditionalTab=Title of additional tab. + * + *@private + */ + __initializeAndParseTabs:function(additionalTab,nameOfAdditionalTab,additionalCloseButton) + { + this.DHTMLSuite_tabObj.className=' DHTMLSuite_tabWidget'; + + window.refToThisTabSet=this; + if(!additionalTab||additionalTab=='undefined'){ + this.DHTMLSuite_tabObj=document.getElementById(this.tabSetParentId); + this.width=this.width+''; + if(this.width.indexOf('%')<0)this.width= this.width+'px'; + this.DHTMLSuite_tabObj.style.width=this.width; + + this.height=this.height+''; + if(this.height.length>0){ + if(this.height.indexOf('%')<0)this.height= this.height+'px'; + this.DHTMLSuite_tabObj.style.height=this.height; + } + + var tabDiv=document.createElement('DIV'); + var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0]; + + this.DHTMLSuite_tabObj.insertBefore(tabDiv,firstDiv); + tabDiv.className='DHTMLSuite_tabContainer'; + this.tabView_countTabs=0; + var tmpTabTitles=this.tabTitles; + // tmpTab titles set to current tab titles-this variable is used in the loop below + + // We don't want to loop through all the tab titles in the object when we add a new one manually. + + }else{ + // A new tab being created dynamically afterwards. + var tabDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[0]; + var firstDiv=this.DHTMLSuite_tabObj.getElementsByTagName('DIV')[1]; + this.initActiveTabIndex=this.tabView_countTabs; + var tmpTabTitles=Array(nameOfAdditionalTab); + // tmpTab titles set to only the new tab + } + for(var no=0;no0){ + if(this.height.indexOf('%')==-1){ + var tmpHeight=(this.height.replace('px','')/1-22); + tabs[no].style.height=tmpHeight+'px'; + }else + tabs[no].style.height=this.height; + } + tabs[no].style.display='none'; + if(tabs[no].id){ + tabs[no].setAttribute('originalId',tabs[no].id); + tabs[no].originalId=tabs[no].id; + } + tabs[no].id='tabView'+this.tabSetParentId+"_"+divCounter; + divCounter++; + } + } + if(additionalTab){ + this.tabView_countTabs++; + }else{ + this.tabView_countTabs=this.tabView_countTabs+this.tabTitles.length; + } + + this.__showTab(this.tabSetParentId,this.initActiveTabIndex,this.outsideObjectRefIndex); + + return this.activeTabIndex; + } + + // }}} + , + + // {{{ __mouseOutEffectForCloseButton() + /** + * + *@private + */ + __mouseOutEffectForCloseButton:function() + { + this.src=this.src.replace('close-over.gif','close.gif'); + } + + // }}} + , + + // {{{ __mouseOverEffectCloseButton() + /** + * + *@private + */ + __mouseOverEffectCloseButton:function() + { + this.src=this.src.replace('close.gif','close-over.gif'); + } + + // }}} + , + + // {{{ __fillTabWithContentFromAjax() + /** + * + *@param Int ajaxIndex=Index of Ajax array + *@param String objId=Id of element where content from Ajax should be displayed + *@param Int tabId=Id of element where content from Ajax should be displayed + * + *@private + */ + __fillTabWithContentFromAjax:function(ajaxIndex,objId,tabId) + { + var obj=document.getElementById('tabView'+objId+'_'+tabId); + obj.innerHTML=this.ajaxObjects[ajaxIndex].response; + } + + // }}} + , + + // {{{ __resetTabIds() + /** + * + *@private + */ + __resetTabIds:function(parentId) + { + var tabTitleCounter=0; + var tabContentCounter=0; + var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); + + for(var no=0;no=0&&divs[no].parentNode.parentNode==this.DHTMLSuite_tabObj){ + divs[no].id='tabTab'+parentId+'_'+tabContentCounter; + tabContentCounter++; + } + + } + this.tabView_countTabs=tabContentCounter; + } + + // }}} + , + + // {{{ getTabIndexByTitle() + /** + * + *@private + */ + getTabIndexByTitle:function(tabTitle) + { + tabTitle=tabTitle.replace(/(.*?) .*$/gi,'$1'); + var divs=this.DHTMLSuite_tabObj.getElementsByTagName('DIV'); + + for(var no=0;no=0){ + var span=divs[no].getElementsByTagName('SPAN')[0]; + var spanTitle=span.innerHTML.replace(/(.*?) .*$/gi,'$1'); + if(spanTitle==tabTitle){ + var tmpId=divs[no].id.split('_'); + return tmpId[tmpId.length-1].replace(/[^0-9]/g,'')/1; + } + } + } + return -1; + } + , + // batur + // {{{ getTabTitle() + /** + * return active tab title + *@public + */ + getTabTitle:function() { + return (this.tabTitles[this.activeTabIndex]); + } + + // }}} +} + +/*[FILE_START:dhtmlSuite-dragDropTree.js] */ +/************************************************************************************************************ +* Drag and drop folder tree +* +* Created: August, 23rd, 2006 +* +* Demos of this class: demo-drag-drop-folder-tree.html +* +* Update log: +* +************************************************************************************************************/ + +var JSTreeObj; +var treeUlCounter = 0; +var nodeId = 1; + +/** +* @constructor +* @class Purpose of class: Transforms an UL,LI list into a folder tree with drag and drop capabilities(See demo). +* @version 1.0 +* @version 1.0 +* +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.JSDragDropTree = function(){ + var idOfTree; + var folderImage; + var plusImage; + var minusImage; + var maximumDepth; + var dragNode_source; + var dragNode_parent; + var dragNode_sourceNextSib; + var dragNode_noSiblings; + + var dragNode_destination; + var floatingContainer; + var dragDropTimer; + var dropTargetIndicator; + var insertAsSub; + var indicator_offsetX; + var indicator_offsetX_sub; + var indicator_offsetY; + var messageMaximumDepthReached; + var ajaxObjects; + var layoutCSS; + var cookieName; + + /* Initial variable values */ + this.folderImage = 'DHTMLSuite_folder.gif'; + this.plusImage = 'DHTMLSuite_plus.gif'; + this.minusImage = 'DHTMLSuite_minus.gif'; + this.maximumDepth = 6; + this.layoutCSS = 'drag-drop-folder-tree.css'; + + this.floatingContainer = document.createElement('UL'); + this.floatingContainer.style.position = 'absolute'; + this.floatingContainer.style.display='none'; + this.floatingContainer.id = 'floatingContainer'; + this.insertAsSub = false; + document.body.appendChild(this.floatingContainer); + this.dragDropTimer = -1; + this.dragNode_noSiblings = false; + this.cookieName = 'DHTMLSuite_expandedNodes'; + + if(document.all){ + this.indicator_offsetX = 1; // Offset position of small black lines indicating where nodes would be dropped. + this.indicator_offsetX_sub = 1; + this.indicator_offsetY = 13; + }else{ + this.indicator_offsetX = 1; // Offset position of small black lines indicating where nodes would be dropped. + this.indicator_offsetX_sub = 3; + this.indicator_offsetY = 5; + } + if(navigator.userAgent.indexOf('Opera')>=0){ + this.indicator_offsetX = 2; // Offset position of small black lines indicating where nodes would be dropped. + this.indicator_offsetX_sub = 3; + this.indicator_offsetY = -7; + } + + this.messageMaximumDepthReached = ''; // Use '' if you don't want to display a message + this.ajaxObjects = new Array(); + + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + var objectIndex; + + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + +} + +/* DHTMLSuite.JSDragDropTree class */ +DHTMLSuite.JSDragDropTree.prototype = { + // {{{ init() + /** + * Initializes the script + * + * @public + */ + init : function(){ + var ind = this.objectIndex; + DHTMLSuite.commonObj.loadCSS(this.layoutCSS); + JSTreeObj = this; + this.__createDropIndicator(); + if(!document.documentElement.onselectstart)document.documentElement.onselectstart = function() { return DHTMLSuite.commonObj.__isTextSelOk(); }; + document.documentElement.ondragstart = document.documentElement.ondragstart = function() { return false; }; + DHTMLSuite.commonObj.__addEventEl(document.documentElement); + var nodeId = 0; + var DHTMLSuite_tree = document.getElementById(this.idOfTree); + var menuItems = DHTMLSuite_tree.getElementsByTagName('LI'); // Get an array of all menu items + for(var no=0;no0 && subItems[0].style.display!='block'){ + this.showHideNode(false,menuItems[no].id); + } + } + } + // }}} + , + // {{{ collapseAll() + /** + * Collapse all tree nodes + * + * + * @public + */ + collapseAll : function(){ + var menuItems = document.getElementById(this.idOfTree).getElementsByTagName('LI'); + for(var no=0;no0 && subItems[0].style.display=='block'){ + this.showHideNode(false,menuItems[no].id); + } + } + } + // }}} + , + // {{{ showHideNode() + /** + * Expand a specific node + * + * @param boolean e - If you call this method manually, set this argument to false(It's not used) + * @param string inputId - Id of node to expand/collapse + * + * @public + */ + showHideNode : function(e,inputId){ + if(inputId){ + if(!document.getElementById(inputId))return; + thisNode = document.getElementById(inputId).getElementsByTagName('IMG')[0]; + }else { + if(document.all)e = event; + var srcEl = DHTMLSuite.commonObj.getSrcElement(e); + thisNode = srcEl; + if(srcEl.tagName=='A')thisNode = srcEl.parentNode.getElementsByTagName('IMG')[0]; + } + if(thisNode.style.visibility=='hidden')return; + var parentNode = thisNode.parentNode; + inputId = parentNode.id.replace(/[^0-9]/g,''); + if(thisNode.src.indexOf(this.plusImage)>=0){ + thisNode.src = thisNode.src.replace(this.plusImage,this.minusImage); + var ul = parentNode.getElementsByTagName('UL')[0]; + ul.style.display='block'; + if(!initExpandedNodes)initExpandedNodes = ','; + if(initExpandedNodes.indexOf(',' + inputId + ',')<0) initExpandedNodes = initExpandedNodes + inputId + ','; + }else{ + thisNode.src = thisNode.src.replace(this.minusImage,this.plusImage); + parentNode.getElementsByTagName('UL')[0].style.display='none'; + initExpandedNodes = initExpandedNodes.replace(',' + inputId,''); + } + DHTMLSuite.commonObj.setCookie(this.cookieName,initExpandedNodes,500); + return false; + } + // }}} + , + // {{{ getSaveString() + /** + * Return save string + * + * @param Object initObj - Only for private use inside the method + * @param String saveString - Only for private use inside the method - you should call this method without arguments. + * + * @return String saveString - A string with the format id-parentId,id-parentId,id-parentId + * @type String + * @public + */ + getSaveString : function(initObj,saveString){ + if(!saveString)var saveString = ''; + if(!initObj){ + initObj = document.getElementById(this.idOfTree); + + } + var lis = initObj.getElementsByTagName('LI'); + + if(lis.length>0){ + var li = lis[0]; + while(li){ + if(li.id){ + if(saveString.length>0)saveString = saveString + ','; + saveString = saveString + li.id.replace(/[^0-9]/gi,''); + saveString = saveString + '-'; + if(li.parentNode.id!=this.idOfTree)saveString = saveString + li.parentNode.parentNode.id.replace(/[^0-9]/gi,''); else saveString = saveString + '0'; + + var ul = li.getElementsByTagName('UL'); + if(ul.length>0){ + saveString = this.getSaveString(ul[0],saveString); + } + } + li = li.nextSibling; + } + } + if(initObj.id == this.idOfTree){ + return saveString; + } + return saveString; + } + // }}} + , + // {{{ __initializeDragProcess() + /** + * Init a drag process + * + * @param event e = Event object + * @private + */ + __initializeDragProcess : function(e){ + if(document.all)e = event; + + var subs = JSTreeObj.floatingContainer.getElementsByTagName('LI'); + if(subs.length>0){ + if(JSTreeObj.dragNode_sourceNextSib){ + JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib); + }else{ + JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source); + } + } + + JSTreeObj.dragNode_source = this.parentNode; + JSTreeObj.dragNode_parent = this.parentNode.parentNode; + JSTreeObj.dragNode_sourceNextSib = false; + + if(JSTreeObj.dragNode_source.nextSibling)JSTreeObj.dragNode_sourceNextSib = JSTreeObj.dragNode_source.nextSibling; + JSTreeObj.dragNode_destination = false; + JSTreeObj.dragDropTimer = 0; + DHTMLSuite.commonObj.__setTextSelOk(false); + JSTreeObj.__waitBeforeDragProcessStarts(); + return false; + } + // }}} + , + // {{{ __waitBeforeDragProcessStarts() + /** + * A small delay before drag is started + * + * @private + */ + __waitBeforeDragProcessStarts : function(){ + if(this.dragDropTimer>=0 && this.dragDropTimer<10){ + this.dragDropTimer = this.dragDropTimer + 1; + setTimeout('JSTreeObj.__waitBeforeDragProcessStarts()',20); + return; + } + if(this.dragDropTimer==10){ + JSTreeObj.floatingContainer.style.display='block'; + JSTreeObj.floatingContainer.appendChild(JSTreeObj.dragNode_source); + } + } + // }}} + , + // {{{ __moveDragableNodes() + /** + * Move dragable nodes + * @param event e - Event object + * + * @private + */ + __moveDragableNodes : function(e,tagType){ + if(JSTreeObj.dragDropTimer<10)return; + if(document.all)e = event; + dragDrop_x = e.clientX/1 + 5 + document.body.scrollLeft; + dragDrop_y = e.clientY/1 + 5 + document.documentElement.scrollTop; + + JSTreeObj.floatingContainer.style.left = dragDrop_x + 'px'; + JSTreeObj.floatingContainer.style.top = dragDrop_y + 'px'; + + var thisObj = DHTMLSuite.commonObj.getSrcElement(e); + var thisObjOrig = DHTMLSuite.commonObj.getSrcElement(e); + if(thisObj.tagName=='A' || thisObj.tagName=='IMG')thisObj = thisObj.parentNode; + + JSTreeObj.dragNode_noSiblings = false; + var tmpVar = thisObj.getAttribute('noSiblings'); + if(!tmpVar)tmpVar = thisObj.noSiblings; + if(tmpVar=='true')JSTreeObj.dragNode_noSiblings=true; + + if(thisObj && tagType){ + JSTreeObj.dragNode_destination = thisObj; + var img = thisObj.getElementsByTagName('IMG')[1]; + var tmpObj= JSTreeObj.dropTargetIndicator; + tmpObj.style.display='block'; + + var eventSourceObj = thisObjOrig; + if(JSTreeObj.dragNode_noSiblings && eventSourceObj.tagName=='IMG')eventSourceObj = eventSourceObj.nextSibling; + + var tmpImg = tmpObj.getElementsByTagName('IMG')[0]; + if(thisObjOrig.tagName=='A' || JSTreeObj.dragNode_noSiblings){ + tmpImg.src = tmpImg.src.replace('ind1','ind2'); + JSTreeObj.insertAsSub = true; + tmpObj.style.left = (DHTMLSuite.commonObj.getLeftPos(eventSourceObj) + JSTreeObj.indicator_offsetX_sub) + 'px'; + }else{ + + tmpImg.src = tmpImg.src.replace('ind2','ind1'); + JSTreeObj.insertAsSub = false; + tmpObj.style.left = (DHTMLSuite.commonObj.getLeftPos(eventSourceObj) + JSTreeObj.indicator_offsetX) + 'px'; + } + + tmpObj.style.top = (DHTMLSuite.commonObj.getTopPos(thisObj) + JSTreeObj.indicator_offsetY) + 'px'; + } + + return false; + + } + // }}} + , + // {{{ __dropDragableNodes() + /** + * Drag process ended - drop nodes + * + * @private + */ + __dropDragableNodes:function(){ + if(JSTreeObj.dragDropTimer<10){ + JSTreeObj.dragDropTimer = -1; + DHTMLSuite.commonObj.__setTextSelOk(true); + return; + } + var showMessage = false; + if(JSTreeObj.dragNode_destination){ // Check depth + var countUp = JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_destination,'up'); + var countDown = JSTreeObj.__getDepthOfABranchInTheTree(JSTreeObj.dragNode_source,'down'); + var countLevels = countUp/1 + countDown/1 + (JSTreeObj.insertAsSub?1:0); + + if(countLevels>JSTreeObj.maximumDepth){ + JSTreeObj.dragNode_destination = false; + showMessage = true; // Used later down in this function + } + } + + if(JSTreeObj.dragNode_destination){ + if(JSTreeObj.insertAsSub){ + var uls = JSTreeObj.dragNode_destination.getElementsByTagName('UL'); + if(uls.length>0){ + ul = uls[0]; + ul.style.display='block'; + + var lis = ul.getElementsByTagName('LI'); + + if(lis.length>0){ // Sub elements exists - drop dragable node before the first one + ul.insertBefore(JSTreeObj.dragNode_source,lis[0]); + }else { // No sub exists - use the appendChild method - This line should not be executed unless there's something wrong in the HTML, i.e empty
      + ul.appendChild(JSTreeObj.dragNode_source); + } + }else{ + var ul = document.createElement('UL'); + ul.style.display='block'; + JSTreeObj.dragNode_destination.appendChild(ul); + ul.appendChild(JSTreeObj.dragNode_source); + } + var img = JSTreeObj.dragNode_destination.getElementsByTagName('IMG')[0]; + img.style.visibility='visible'; + img.src = img.src.replace(JSTreeObj.plusImage,JSTreeObj.minusImage); + + }else{ + if(JSTreeObj.dragNode_destination.nextSibling){ + var nextSib = JSTreeObj.dragNode_destination.nextSibling; + nextSib.parentNode.insertBefore(JSTreeObj.dragNode_source,nextSib); + }else{ + JSTreeObj.dragNode_destination.parentNode.appendChild(JSTreeObj.dragNode_source); + } + } + /* Clear parent object */ + var tmpObj = JSTreeObj.dragNode_parent; + var lis = tmpObj.getElementsByTagName('LI'); + if(lis.length==0){ + var img = tmpObj.parentNode.getElementsByTagName('IMG')[0]; + img.style.visibility='hidden'; // Hide [+],[-] icon + DHTMLSuite.discardElement(tmpObj); + } + }else{ + // Putting the item back to it's original location + + if(JSTreeObj.dragNode_sourceNextSib){ + JSTreeObj.dragNode_parent.insertBefore(JSTreeObj.dragNode_source,JSTreeObj.dragNode_sourceNextSib); + }else{ + JSTreeObj.dragNode_parent.appendChild(JSTreeObj.dragNode_source); + } + + } + JSTreeObj.dropTargetIndicator.style.display='none'; + JSTreeObj.dragDropTimer = -1; + DHTMLSuite.commonObj.__setTextSelOk(true); + if(showMessage && JSTreeObj.messageMaximumDepthReached)alert(JSTreeObj.messageMaximumDepthReached); + } + // }}} + , + // {{{ __createDropIndicator() + /** + * Create small black lines indicating where items will be dropped + * + * @private + */ + __createDropIndicator : function(){ + this.dropTargetIndicator = document.createElement('DIV'); + this.dropTargetIndicator.style.zIndex = 240000; + this.dropTargetIndicator.style.position = 'absolute'; + this.dropTargetIndicator.style.display='none'; + var img = document.createElement('IMG'); + img.src = DHTMLSuite.configObj.imagePath + 'drag-drop-tree/' + 'dragDrop_ind1.gif'; + img.id = 'dragDropIndicatorImage'; + this.dropTargetIndicator.appendChild(img); + document.body.appendChild(this.dropTargetIndicator); + } + // }}} + , + // {{{ __getDepthOfABranchInTheTree() + /** + * Count depth of a branch + * + * @private + */ + __getDepthOfABranchInTheTree : function(obj,direction,stopAtObject){ + var countLevels = 0; + if(direction=='up'){ + while(obj.parentNode && obj.parentNode!=stopAtObject){ + obj = obj.parentNode; + if(obj.tagName=='UL')countLevels = countLevels/1 +1; + } + return countLevels; + } + + if(direction=='down'){ + var subObjects = obj.getElementsByTagName('LI'); + for(var no=0;nodemo). +* @version 1.0 +* @version 1.0 +* +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.ajaxUtil = function(){ + var ajaxObjects; + this.ajaxObjects = new Array(); + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + var objectIndex; + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + +} + +DHTMLSuite.ajaxUtil.prototype = { + // {{{ sendRequest() + /** + * Sends an ajax request to the server + * + * @param String url = Path on the server + * @param String paramString - Parameters, Example: "varA=2&varB=3"; + * @param String functionNameOnComplete = Function to execute on complete, example: "myFunction". The ajax object will be sent to this function and you can get the response from the "reponse" attribute. + * NB! This ajax object will be cleared automatically by the script after a 3 second delay. + * + * @public + */ + sendRequest : function(url,paramString,functionNameOnComplete){ + var ind = this.objectIndex; + var ajaxIndex = this.ajaxObjects.length; + try{ + this.ajaxObjects[ajaxIndex] = new sack(); + }catch(e){ + alert('Could not create ajax object. Please make sure that ajax.js is included'); + } + if(paramString){ + var params = this.__getArrayByParamString(paramString); + for(var no=0;nodemo).
      +* The pane splitter, window widget and the ajax tooltip script are also using this class to put external content into HTML elements. +* @version 1.0 +* @version 1.0 +* +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +**/ + +DHTMLSuite.dynamicContent = function(){ + var enableCache; // Cache enabled. + var jsCache; + var ajaxObjects; + var waitMessage; + + this.enableCache = true; + this.jsCache = new Object(); + this.ajaxObjects = new Array(); + this.waitMessage = 'Loading content - please wait...'; + this.waitImage = 'dynamic-content/ajax-loader-darkblue.gif'; + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + var objectIndex; + + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + +} + +DHTMLSuite.dynamicContent.prototype = { + + // {{{ loadContent() + /** + * Load content from external files into an element on your web page. + * + * @param String divId = Id of HTML element + * @param String url = Path to content on the server(Local content only) + * @param String functionToCallOnLoaded = Function to call when ajax is finished. This string will be evaulated, example of string: "fixContent()" (with the quotes). + * + * @public + */ + loadContent : function(divId,url,functionToCallOnLoaded){ + + var ind = this.objectIndex; + if(this.enableCache && this.jsCache[url]){ + document.getElementById(divId).innerHTML = this.jsCache[url]; + DHTMLSuite.commonObj.__evaluateJs(divId); + DHTMLSuite.commonObj.__evaluateCss(divId); + if(functionToCallOnLoaded)eval(functionToCallOnLoaded); + return; + } + var ajaxIndex = 0; + + /* Generating please wait message */ + var waitMessageToShow = ''; + if(this.waitImage){ // Wait image exists ? + waitMessageToShow = waitMessageToShow + '
      '; + } + if(this.waitMessage){ // Wait message exists ? + waitMessageToShow = waitMessageToShow + '
      ' + this.waitMessage + '
      '; + } + + if(this.waitMessage!=null && this.waitImage!=null){ + try{ + if(waitMessageToShow.length>0)document.getElementById(divId).innerHTML=waitMessageToShow; + }catch(e){ + } + } + waitMessageToShow = false; + var ajaxIndex = this.ajaxObjects.length; + + try{ + this.ajaxObjects[ajaxIndex] = new sack(); + }catch(e){ + alert('Could not create ajax object. Please make sure that ajax.js is included'); + } + + if(url.indexOf('?')>=0){ // Get variables in the url + this.ajaxObjects[ajaxIndex].method='GET'; // Change method to get + var string = url.substring(url.indexOf('?')); // Extract get variables + url = url.replace(string,''); + string = string.replace('?',''); + var items = string.split(/&/g); + for(var no=0;no tag. + * + * @public + */ + setCache : function(enableCache){ + this.enableCache = enableCache; + } + // }}} + , + // {{{ __ajax_showContent() + /** + * Evaluate Javascript in the inserted content + * + * @private + */ + __ajax_showContent :function(divId,ajaxIndex,url,functionToCallOnLoaded){ + document.getElementById(divId).innerHTML = ''; + document.getElementById(divId).innerHTML = this.ajaxObjects[ajaxIndex].response; + if(this.enableCache){ // Cache is enabled + this.jsCache[url] = document.getElementById(divId).innerHTML + ''; // Put content into cache + } + DHTMLSuite.commonObj.__evaluateJs(divId); // Call private method which evaluates JS content + DHTMLSuite.commonObj.__evaluateCss(divId); // Call private method which evaluates JS content + if(functionToCallOnLoaded)eval(functionToCallOnLoaded); + this.ajaxObjects[ajaxIndex] = null; // Clear sack object + return false; + } + // }}} + , + // {{{ __ajax_displayError() + /** + * Display error message when the request failed. + * + * @private + */ + __ajax_displayError : function(divId,ajaxIndex,url,functionToCallOnLoaded){ + document.getElementById(divId).innerHTML = '

      Message from DHTMLSuite.dynamicContent

      The ajax request for ' + url + ' failed

      '; + } + // }}} +} + +/*[FILE_START:dhtmlSuite-slider.js] */ +/************************************************************************************************************ +* +* DHTML slider +* +* Created: August, 25th, 2006 +* @class Purpose of class: Display a slider on a web page. +* +* Demos of this class: demo-slider-1.html +* +* Update log: +* +************************************************************************************************************/ + +DHTMLSuite.sliderObjects = new Array(); // Array of slider objects. Used in events when "this" refers to the tag trigger the event and not the object. +DHTMLSuite.indexOfCurrentlyActiveSlider = false; // Index of currently active slider(i.e. index in the DHTMLSuite.sliderObjects array) +DHTMLSuite.slider_generalMouseEventsAdded = false; // Only assign mouse move and mouseup events once. This variable make sure that happens. + +/** +* @constructor +* @class Purpose of class: Display a DHTML slider on a web page. This slider could either be displayed horizontally or vertically(demo 1 and demo 2). +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +* +**/ +DHTMLSuite.slider = function(){ + var width; // Width of slider + var height; // height of slider + var targetObj; // Object where slider will be added. + var sliderWidth; // Width of slider image. this is needed in order to position the slider and calculate values correctly. + var sliderDirection; // Horizontal or vertical + var functionToCallOnChange; // Function to call when the slider is moved. + var layoutCss; + var sliderMaxValue; // Maximum value to return from slider + var sliderMinValue; // Minimum value to return from slider + var initialValue; // Initial value of slider + var sliderSize; // Size of sliding area. + var directionOfPointer; // Direction of slider pointer; + var slideInProcessTimer; // Private variable used to determine if slide is in progress or not. + var indexThisSlider; // Index of object in the DHTMLSuite.sliderObjects array + var numberOfSteps; // Hardcoded steps + var stepLinesVisibility; // Visibility of lines indicating where the slider steps are + + var slide_event_pos; // X position of mouse when slider drag starts + var slide_start_pos; // X position of slider when drag starts + var sliderHandleImg; // Reference to the small slider handle + var sliderName; // A name you can use to identify a slider. Useful if you have more than one slider, but only one onchange event. + var sliderValueReversed; // Variable indicating if the value of the slider is reversed(i.e. max at left and min at right) + this.sliderWidth = 9; // Initial width of slider. + this.layoutCss = 'slider.css'; // Default css file + this.sliderDirection = 'hor'; // Horizontal is default + this.width = 0; // Initial widht + this.height = 0; // Initial height + this.sliderMaxValue = 100; // Default max value to return from slider + this.sliderMinValue = 0; // Default min value to return from slider + this.initialValue = 0; // Default initial value of slider + this.targetObj = false; // Set target obj to false initially. + this.directionOfPointer = 'up'; // Default pointer direction for slider handle. + this.slideInProcessTimer = -1; + this.sliderName = ''; + this.numberOfSteps = false; + this.stepLinesVisibility = true; + this.sliderValueReversed = false; // Default value of sliderValueReversed, i.e. max at right, min at left or max at top, min at bottom. + + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + var objectIndex; + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + +} + +DHTMLSuite.slider.prototype = { + + // {{{ init() + /** + * Initializes the script, i.e. creates the slider + * + * + * @public + */ + + init : function() // Initializes the script + { + if(!this.targetObj){ + alert('Error! - No target for slider specified'); + return; + } + + this.__setWidthAndHeightDynamically(); + DHTMLSuite.commonObj.loadCSS(this.layoutCss); + this.__createSlider(); + if(!document.documentElement.onselectstart)document.documentElement.onselectstart = function() { return DHTMLSuite.commonObj.__isTextSelOk(); }; + + } + // }}} + , + // {{{ setSliderTarget(divId) + /** + * Specify where to insert the slider + * + * @param Object targetRef - Id of element where the slider will be created inside(There shouldn't be any content inside this div) + * + * @public + */ + setSliderTarget : function(targetRef){ + targetRef = DHTMLSuite.commonObj.getEl(targetRef); + this.targetObj = targetRef; + } + // }}} + , + // {{{ setSliderDirection(newDirection) + /** + * Specify where to insert the slider + * + * @param String newDirection - New slider direction. Possible valuse: "hor" or "ver" + * + * @public + */ + setSliderDirection : function(newDirection){ + newDirection = newDirection + ''; + newDirection = newDirection.toLowerCase(); + if(newDirection!='hor' && newDirection!='ver'){ + alert('Invalid slider direction - possible values: "hor" or "ver"'); + return; + } + this.sliderDirection = newDirection; + } + // }}} + , + // {{{ setSliderWidth(newWidth) + /** + * Specify width of slider - if now width is specified, the script will try to measure the height of width of the element where it is inserted. + * + * @param String newWidth - Slider width(numeric or percentage) example: 100 or 90% + * + * @public + */ + setSliderWidth : function(newWidth){ + newWidth = newWidth + ''; + if(newWidth.indexOf('%')==-1)newWidth = newWidth + 'px'; + this.width = newWidth; + } + // }}} + , + // {{{ setSliderHeight(newHeight) + /** + * Specify height of slider - if now width is specified, the script will try to measure the height of width of the element where it is inserted. + * + * @param String newHeight - Slider width(numeric or percentage) example: 100 or 90% + * + * @public + */ + setSliderHeight : function(newHeight){ + newHeight = newHeight + ''; + if(newHeight.indexOf('%')==-1)newHeight = newHeight + 'px'; + this.height = height; + } + // }}} + , + // {{{ setSliderReversed() + /** + * Reverse slider, i.e. max at left instead of right or at bottom instead of top + * + * + * @public + */ + setSliderReversed : function(){ + this.sliderValueReversed = true; + } + // }}} + , + // {{{ setOnChangeEvent(nameOfFunction) + /** + * Specify which function to call when the slider has been moved. + * + * @param String nameOfFunction - Name of function to call. + * + * @public + */ + setOnChangeEvent : function(nameOfFunction){ + this.functionToCallOnChange = nameOfFunction; + + } + // }}} + , + // {{{ setSliderMaxValue(newMaxValue) + /** + * Set maximum value of slider + * + * @param int newMaxValue - New slider max value + * + * @public + */ + setSliderMaxValue : function(newMaxValue){ + this.sliderMaxValue = newMaxValue; + + } + // }}} + , + // {{{ setSliderMinValue(newMinValue) + /** + * Set minimum value of slider + * + * @param int newMinValue - New slider min value + * + * @public + */ + setSliderMinValue : function(newMinValue){ + this.sliderMinValue = newMinValue; + + } + // }}} + , + // {{{ setSliderName(nameOfSlider) + /** + * Specify name of slider. + * + * @param String nameOfSlider - Name of function to call. + * + * @public + */ + setSliderName : function(nameOfSlider){ + this.sliderName = nameOfSlider; + + } + // }}} + , + // {{{ setLayoutCss(nameOfNewCssFile) + /** + * Specify a new CSS file for the slider(i.e. not using default css file which is slider.css) + * + * @param String nameOfNewCssFile - Name of new css file. + * + * @public + */ + setLayoutCss : function(nameOfNewCssFile){ + this.layoutCss = nameOfNewCssFile; + } + // }}} + , + // {{{ setLayoutCss(nameOfNewCssFile) + /** + * Specify a new CSS file for the slider(i.e. not using default css file which is slider.css) + * + * @param String nameOfNewCssFile - Name of new css file. + * + * @public + */ + setInitialValue : function(newInitialValue){ + this.initialValue = newInitialValue; + } + // }}} + , + // {{{ setSliderPointerDirection(directionOfPointer) + /** + * In which direction should the slider handle point. + * + * @param String directionOfPointer - In which direction should the slider handle point(possible values: 'up','down','left','right' + * + * @public + */ + setSliderPointerDirection : function(directionOfPointer){ + this.directionOfPointer = directionOfPointer; + } + // }}} + , + // {{{ setSliderValue(newValue) + /** + * Set new position of slider manually + * + * @param Int newValue - New value of slider + * + * @public + */ + setSliderValue : function(newValue){ + var position = Math.floor((newValue / this.sliderMaxValue) * this.sliderSize); + if(this.sliderDirection=='hor'){ + this.sliderHandleImg.style.left = position + 'px'; + }else{ + this.sliderHandleImg.style.top = position + 'px'; + } + } + // }}} + , + // {{{ setNumberOfSliderSteps(numberOfSteps) + /** + * Divide slider into steps, i.e. instead of having a smooth slide. + * + * @param Int numberOfSteps - Number of steps + * + * @public + */ + setNumberOfSliderSteps : function(numberOfSteps){ + this.numberOfSteps = numberOfSteps; + } + // }}} + , + // {{{ setStepLinesVisible(visible) + /** + * Divide slider into steps. + * + * @param Boolean visible - When using static steps, make lines indicating steps visible or hidden(true = visible(default), false = hidden) + * + * @public + */ + setStepLinesVisible : function(visible){ + this.stepLinesVisibility = visible; + } + // }}} + , + // {{{ __setWidthAndHeightDynamically() + /** + * Automatically set height and width of slider. + * + * + * @private + */ + __setWidthAndHeightDynamically : function(){ + // No width or height specified - try to measure it from the size of parent box + + if(!this.width || this.width==0)this.width = this.targetObj.clientWidth+''; + if(!this.height || this.height==0)this.height = this.targetObj.clientHeight+''; + if(!this.width || this.width==0)this.width = this.targetObj.offsetWidth+''; + if(!this.height || this.height==0)this.height = this.targetObj.offsetHeight+''; + + if(this.width==0)return; + if(this.height==0)return; + + if(this.width.indexOf('px')==-1 && this.width.indexOf('%')==-1)this.width = this.width + 'px'; + if(this.height.indexOf('px')==-1 && this.height.indexOf('%')==-1)this.height = this.height + 'px'; + + } + // }}} + , + // {{{ __createSlider() + /** + * Creates the HTML for the slider dynamically + * + * + * @private + */ + __createSlider : function(initWidth){ + if(this.targetObj.clientWidth==0 || initWidth==0){ + var timeoutTime = 100; + setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + this.objectIndex + '].__createSlider(' + this.targetObj.clientWidth + ')',timeoutTime); + return; + } + this.__setWidthAndHeightDynamically(); + this.indexThisSlider = DHTMLSuite.sliderObjects.length; + DHTMLSuite.sliderObjects[this.indexThisSlider] = this; + + window.refToThisObject = this; + + // Creates a parent div for the slider + var div = document.createElement('DIV'); + + div.style.width = this.width; + div.style.cursor = 'default'; + div.style.height = this.height; + div.style.position = 'relative'; + div.id = 'sliderNumber' + this.indexThisSlider; // the numeric part of this id is used inside the __setPositionFromClick method + div.onmousedown = this.__setPositionFromClick; + DHTMLSuite.commonObj.__addEventEl(div); + this.targetObj.appendChild(div); + + var sliderObj = document.createElement('DIV'); + + if(this.sliderDirection=='hor'){ // Horizontal slider. + sliderObj.className='DHTMLSuite_slider_horizontal'; + sliderObj.style.width = div.clientWidth + 'px'; + this.sliderSize = div.offsetWidth - this.sliderWidth; + + // Creating slider handle image. + var sliderHandle = document.createElement('IMG'); + var srcHandle = 'slider_handle_down.gif'; + sliderHandle.style.bottom = '2px'; + if(this.directionOfPointer=='up'){ + srcHandle = 'slider_handle_up.gif'; + sliderHandle.style.bottom = '0px'; + } + sliderHandle.src = DHTMLSuite.configObj.imagePath + 'slider/' + srcHandle; + div.appendChild(sliderHandle); + + // Find initial left position of slider + var leftPos; + if(this.sliderValueReversed){ + leftPos = Math.round(((this.sliderMaxValue - this.initialValue) / this.sliderMaxValue) * this.sliderSize) -1; + }else{ + leftPos = Math.round((this.initialValue / this.sliderMaxValue) * this.sliderSize); + } + sliderHandle.style.left = leftPos + 'px'; + + }else{ + sliderObj.className='DHTMLSuite_slider_vertical'; + sliderObj.style.height = div.clientHeight + 'px'; + this.sliderSize = div.clientHeight - this.sliderWidth; + + // Creating slider handle image. + var sliderHandle = document.createElement('IMG'); + var srcHandle = 'slider_handle_right.gif'; + sliderHandle.style.left = '0px'; + if(this.directionOfPointer=='left'){ + srcHandle = 'slider_handle_left.gif'; + sliderHandle.style.left = '0px'; + } + sliderHandle.src = DHTMLSuite.configObj.imagePath + 'slider/' + srcHandle; + div.appendChild(sliderHandle); + + // Find initial left position of slider + var topPos; + if(!this.sliderValueReversed){ + topPos = Math.floor(((this.sliderMaxValue - this.initialValue) / this.sliderMaxValue) * this.sliderSize); + }else{ + topPos = Math.floor((this.initialValue / this.sliderMaxValue) * this.sliderSize); + } + + sliderHandle.style.top = topPos + 'px'; + + } + + sliderHandle.id = 'sliderForObject' + this.indexThisSlider; + sliderHandle.style.position = 'absolute'; + sliderHandle.style.zIndex = 5; + sliderHandle.onmousedown = this.__initializeSliderDrag; + sliderHandle.ondragstart = function() { return false; }; + sliderHandle.onselectstart = function() { return false; }; + DHTMLSuite.commonObj.__addEventEl(sliderHandle); + this.sliderHandleImg = sliderHandle; + + if(!DHTMLSuite.slider_generalMouseEventsAdded){ + // Adding onmousemove event to the tag + DHTMLSuite.commonObj.addEvent(document.documentElement,"mousemove",this.__moveSlider); + // Adding onmouseup event to the tag. + DHTMLSuite.commonObj.addEvent(document.documentElement,"mouseup",this.__stopSlideProcess); + DHTMLSuite.slider_generalMouseEventsAdded = true; + } + + sliderObj.innerHTML = ''; // In order to get a correct height/width of the div + div.appendChild(sliderObj); + + if(this.numberOfSteps && this.stepLinesVisibility){ // Number of steps defined, create graphical lines + var stepSize = this.sliderSize / this.numberOfSteps; + for(var no=0;no<=this.numberOfSteps;no++){ + var lineDiv = document.createElement('DIV'); + lineDiv.style.position = 'absolute'; + lineDiv.innerHTML = ''; + div.appendChild(lineDiv); + if(this.sliderDirection=='hor'){ + lineDiv.className='DHTMLSuite_smallLines_vertical'; + lineDiv.style.left = Math.floor((stepSize * no) + (this.sliderWidth/2)) + 'px'; + }else{ + lineDiv.className='DHTMLSuite_smallLines_horizontal'; + lineDiv.style.top = Math.floor((stepSize * no) + (this.sliderWidth/2)) + 'px'; + lineDiv.style.left = '14px'; + } + + } + } + + } + // }}} + , + // {{{ __initializeSliderDrag() + /** + * Init slider drag + * + * + * @private + */ + __initializeSliderDrag : function(e){ + if(document.all)e = event; + DHTMLSuite.commonObj.__setTextSelOk(false); + var numIndex = this.id.replace(/[^0-9]/gi,''); // Get index in the DHTMLSuite.sliderObject array. We get this from the id of the slider image(i.e. "this"). + var sliderObj = DHTMLSuite.sliderObjects[numIndex]; + DHTMLSuite.indexOfCurrentlyActiveSlider = numIndex; + sliderObj.slideInProcessTimer = 0; + if(sliderObj.sliderDirection=='hor'){ + sliderObj.slide_event_pos = e.clientX; // Get start x position of mouse pointer + sliderObj.slide_start_pos = this.style.left.replace('px','')/1; // Get x position of slider + }else{ + sliderObj.slide_event_pos = e.clientY; // Get start x position of mouse pointer + sliderObj.slide_start_pos = this.style.top.replace('px','')/1; // Get x position of slider + } + + sliderObj.__waitBeforeSliderDragStarts(); + return false; // Firefox need this line. + } + // }}} + , + // {{{ __setPositionFromClick() + /** + * Set position from click - click on slider - move handle to the mouse pointer + * + * + * @private + */ + __setPositionFromClick : function(e){ + if(document.all)e = event; + // Tag of element triggering this event. If it's something else than a
      , return without doing anything, i.e. mouse down on slider handle. + if (e.target) srcEvent = e.target; + else if (e.srcElement) srcEvent = e.srcElement; + if (srcEvent.nodeType == 3) // defeat Safari bug + srcEvent = srcEvent.parentNode; + if(srcEvent.tagName!='DIV')return; + + var numIndex = this.id.replace(/[^0-9]/gi,''); // Get index in the DHTMLSuite.sliderObject array. We get this from the id of the slider image(i.e. "this"). + var sliderObj = DHTMLSuite.sliderObjects[numIndex]; + + if(sliderObj.numberOfSteps){ + modValue = sliderObj.sliderSize / sliderObj.numberOfSteps; // Find value to calculate modulus by + } + + if(sliderObj.sliderDirection=='hor'){ + var handlePos = (e.clientX - DHTMLSuite.commonObj.getLeftPos(this) - Math.ceil(sliderObj.sliderWidth/2)); + }else{ + var handlePos = (e.clientY - DHTMLSuite.commonObj.getTopPos(this) - Math.ceil(sliderObj.sliderWidth/2)); + } + if(sliderObj.numberOfSteps){ // Static steps defined + var mod = handlePos % modValue; // Calculate modulus + if(mod>(modValue/2))mod = modValue-mod; else mod*=-1; // Should we move the slider handle left or right? + handlePos = handlePos + mod; + } + if(handlePos<0)handlePos = 0; // Don't allow negative values + if(handlePos > sliderObj.sliderSize)handlePos = sliderObj.sliderSize; // Don't allow values larger the slider size + + if(sliderObj.sliderDirection=='hor'){ + sliderObj.sliderHandleImg.style.left = handlePos + 'px'; + if(!sliderObj.sliderValueReversed){ + returnValue = Math.round((handlePos/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); + }else{ + returnValue = Math.round(((sliderObj.sliderSize - handlePos)/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); + } + }else{ + sliderObj.sliderHandleImg.style.top = handlePos + 'px'; + if(sliderObj.sliderValueReversed){ + returnValue = Math.round((handlePos/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); + }else{ + returnValue = Math.round(((sliderObj.sliderSize - handlePos)/sliderObj.sliderSize) * (sliderObj.sliderMaxValue - sliderObj.sliderMinValue)); + } + } + returnValue = returnValue + sliderObj.sliderMinValue; + + + if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange + '(' + returnValue + ',"' + sliderObj.sliderName + '","click")'); + + DHTMLSuite.indexOfCurrentlyActiveSlider = numIndex; + sliderObj.slideInProcessTimer = 10; + if(sliderObj.sliderDirection=='hor'){ + sliderObj.slide_event_pos = e.clientX; // Get start x position of mouse pointer + sliderObj.slide_start_pos = handlePos; // Get x position of slider + }else{ + sliderObj.slide_event_pos = e.clientY; // Get start x position of mouse pointer + sliderObj.slide_start_pos = handlePos; // Get x position of slider + } + DHTMLSuite.commonObj.__setTextSelOk(false); + + } + // }}} + , + // {{{ __waitBeforeSliderDragStarts() + /** + * A small delay before the drag process starts. + * + * + * @private + */ + __waitBeforeSliderDragStarts : function(){ + if(this.slideInProcessTimer<10 && this.slideInProcessTimer>=0){ + this.slideInProcessTimer+=2; + window.refToThisSlider = this; + setTimeout('window.refToThisSlider.__waitBeforeSliderDragStarts()',5); + } + + } + // }}} + , + // {{{ __moveSlider() + /** + * Move the slider + * + * + * @private + */ + __moveSlider : function(e){ + if(DHTMLSuite.indexOfCurrentlyActiveSlider===false)return; + var sliderObj = DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider]; + if(document.all)e = event; + if(sliderObj.slideInProcessTimer<10)return; + + var returnValue = sliderObj.__getSliderValue(e); + + + if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange + '(' + returnValue + ',"' + sliderObj.sliderName + '","move")'); + + } + , + __getSliderValue : function(e) { + var returnValue; + // Static steps defined ? + if(this.numberOfSteps){ // Find value to calculate modulus by + modValue = this.sliderSize / this.numberOfSteps; + } + if(this.sliderDirection=='hor'){ + var handlePos = e.clientX - this.slide_event_pos + this.slide_start_pos; + }else{ + var handlePos = e.clientY - this.slide_event_pos + this.slide_start_pos; + } + if(this.numberOfSteps){ + var mod = handlePos % modValue; + if(mod>(modValue/2))mod = modValue-mod; else mod*=-1; + handlePos = handlePos + mod; + } + if(handlePos<0)handlePos = 0; + if(handlePos > this.sliderSize)handlePos = this.sliderSize; + + if(this.sliderDirection=='hor'){ + this.sliderHandleImg.style.left = handlePos + 'px'; + if(!this.sliderValueReversed){ + returnValue = Math.round((handlePos/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); + }else{ + returnValue = Math.round(((this.sliderSize - handlePos)/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); + } + }else{ + this.sliderHandleImg.style.top = handlePos + 'px'; + if(this.sliderValueReversed){ + returnValue = Math.round((handlePos/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); + }else{ + returnValue = Math.round(((this.sliderSize - handlePos)/this.sliderSize) * (this.sliderMaxValue - this.sliderMinValue)); + } + } + returnValue = returnValue + this.sliderMinValue; + return returnValue; + + } + // }}} + , + // {{{ __stopSlideProcess() + /** + * Stop the drag process + * + * + * @private + */ + __stopSlideProcess : function(e){ + if(document.all)e = event; + DHTMLSuite.commonObj.__setTextSelOk(true); + if(!DHTMLSuite.indexOfCurrentlyActiveSlider)return; + var sliderObj = DHTMLSuite.sliderObjects[DHTMLSuite.indexOfCurrentlyActiveSlider]; + sliderObj.slideInProcessTimer = -1; + var returnValue = sliderObj.__getSliderValue(e); + if(sliderObj.functionToCallOnChange)eval(sliderObj.functionToCallOnChange + '(' + returnValue + ',"' + sliderObj.sliderName + '","mouseup")'); + } +} + +/*[FILE_START:dhtmlSuite-modalMessage.js] */ +/************************************************************************************************************ +* DHTML modal dialog box +* +* Created: August, 26th, 2006 +* @class Purpose of class: Display a modal dialog box on the screen. +* +* Css files used by this script: modal-message.css +* +* Demos of this class: demo-modal-message-1.html +* +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class Purpose of class: Display a modal DHTML message on the page. All other page controls will be disabled until the message is closed(demo). +* @param Array - Associative array of properties. These properties can also be set by calling invidiual set-methods. Possible keys in this array:
      +* url - Url to file displayed in the message +* htmlOfModalMessage - Static HTML to display. +* domRef - Reference to dom element. This dom element will be cloned and displayed inside the message box. You will typically set display:none or visibility:hidden on this element +* width - Width of box +* height - Height of box +* cssClassOfMessageBox - Alternative css class for the message box +* shadowOffset - Size of drop shadow in pixels +* shadowDivVisible - Shadow visible (default = true) +* isModal - Is the dialog modal ? (default = true) +* +* @version 1.0 +* @author Alf Magne Kalleland(www.dhtmlgoodies.com) +*/ + +DHTMLSuite.modalMessage = function(props){ + var url; // url of modal message + var htmlOfModalMessage; // html of modal message + var domRef; // Reference to DOM element + + var divs_transparentDiv; // Transparent div covering page content + var divs_content; // Modal message div. + var iframeEl; // Iframe element used to cover select boxes in ie + var layoutCss; // Name of css file; + var width; // Width of message box + var height; // Height of message box + var isModal; // Is the modal message modal ? + + var existingBodyOverFlowStyle; // Existing body overflow css + var dynContentObj; // Reference to dynamic content object + var cssClassOfMessageBox; // Alternative css class of message box - in case you want a different appearance on one of them + var shadowDivVisible; // Shadow div visible ? + var shadowOffset; // X and Y offset of shadow(pixels from content box) + + var objectIndex; + + this.url = ''; // Default url is blank + this.htmlOfModalMessage = ''; // Default message is blank + this.layoutCss = 'modal-message.css'; // Default CSS file + this.height = 200; // Default height of modal message + this.width = 400; // Default width of modal message + this.cssClassOfMessageBox = false; // Default alternative css class for the message box + this.shadowDivVisible = true; // Shadow div is visible by default + this.shadowOffset = 5; // Default shadow offset. + this.isModal = true; + + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + var ind = this.objectIndex; + + DHTMLSuite.commonObj.addEvent(window,"resize",function() { DHTMLSuite.variableStorage.arrayDSObjects[ind].__resizeTransparentDiv(); }); + + if(props)this.__setInitialProps(props); +} + +DHTMLSuite.modalMessage.prototype = { + // {{{ __setInitialProps + /** + * Save properties sent to the constructor. + * + * @private + */ + __setInitialProps : function(props){ + if(props.url)this.setSource(props.url); + if(props.htmlOfModalMessage)this.setHtmlContent(props.htmlOfModalMessage); + if(props.domRef)this.setDomReference(props.domRef); + if(props.width)this.width = props.width; + if(props.height)this.height = props.height; + if(props.cssClassOfMessageBox)this.cssClassOfMessageBox = props.cssClassOfMessageBox; + if(props.shadowOffset)this.shadowOffset = props.shadowOffset; + if(props.shadowDivVisible)this.shadowDivVisible = props.shadowDivVisible; + if(props.isModal || props.isModal===false || props.isModal===0)this.isModal = props.isModal; + if(props.waitMessage)this.setWaitMessage(waitMessage); + } + // }}} + , + // {{{ setIsModal(urlOfSource) + /** + * Specify if the box should be modal, i.e. a transparent div behind the box covering page content. + * + * @public + */ + setIsModal : function(isModal){ + this.isModal = isModal; + } + // }}} + , + // {{{ setSource(urlOfSource) + /** + * Set source of the modal dialog box + * + * + * @public + */ + setSource : function(urlOfSource){ + if(urlOfSource)this.__clearProperties(); + this.url = urlOfSource; + } + // }}} + , + // {{{ setHtmlContent(newHtmlContent) + /** + * Setting static HTML content for the modal dialog box. + * + * @param String newHtmlContent = Static HTML content of box + * + * @public + */ + setHtmlContent : function(newHtmlContent){ + if(newHtmlContent)this.__clearProperties(); + this.htmlOfModalMessage = newHtmlContent; + } + // }}} + , + // {{{ setDomReference + /** + * Specify reference to DOM element which will be displayed inside the modal message box. + * + * @param Object domRef = Dom reference + * + * @public + */ + setDomReference : function(domRef){ + if(domRef)this.__clearProperties(); + if(domRef)domRef = DHTMLSuite.commonObj.getEl(domRef); + if(domRef){ + domRef = domRef.cloneNode(true); + } + this.domRef = domRef; + } + // }}} + , + // {{{ setSize + /** + * Set the size of the modal dialog box + * + * @param int width = width of box + * @param int height = height of box + * + * @public + */ + setSize : function(width,height){ + if(width)this.width = width; + if(height)this.height = height; + } + // }}} + , + // {{{ setCssClassMessageBox(newCssClass) + /** + * Assign the message box to a new css class.(in case you wants a different appearance on one of them) + * + * @param String newCssClass = Name of new css class (Pass false if you want to change back to default) + * + * @public + */ + setCssClassMessageBox : function(newCssClass){ + this.cssClassOfMessageBox = newCssClass; + if(this.divs_content){ + if(this.cssClassOfMessageBox) + this.divs_content.className=this.cssClassOfMessageBox; + else + this.divs_content.className='modalDialog_contentDiv'; + } + + } + // }}} + , + // {{{ setShadowOffset(newShadowOffset) + /** + * Specify the size of shadow + * + * @param Int newShadowOffset = Offset of shadow div(in pixels from message box - x and y) + * + * @public + */ + setShadowOffset : function(newShadowOffset){ + this.shadowOffset = newShadowOffset + + } + // }}} + , + // {{{ setWaitMessage(newMessage) + /** + * Set a wait message when Ajax is busy inserting content + * + * @param String newMessage = New wait message + * + * @public + */ + setWaitMessage : function(newMessage){ + if(!this.dynContentObj){ + try{ + this.dynContentObj = new DHTMLSuite.dynamicContent(); // Creating dynamic content object if it doesn't already exist. + }catch(e){ + alert('You need to include dhtmlSuite-dynamicContent.js'); + } + } + this.dynContentObj.setWaitMessage(newMessage); // Calling the DHTMLSuite.dynamicContent setWaitMessage + } + // }}} + , + // {{{ setWaitImage(newImage) + /** + * Set a wait Image when Ajax is busy inserting content + * + * @param String newImage = New wait Image + * + * @public + */ + setWaitImage : function(newImage){ + if(!this.dynContentObj){ + try{ + this.dynContentObj = new DHTMLSuite.dynamicContent(); // Creating dynamic content object if it doesn't already exist. + }catch(e){ + alert('You need to include dhtmlSuite-dynamicContent.js'); + } + } + this.dynContentObj.setWaitImage(newImage); // Calling the DHTMLSuite.dynamicContent setWaitImage + } + // }}} + , + // {{{ setCache() + /** + * Enable or disable cache for the ajax object + * + * @param Boolean cacheStatus = false = off, true = on + * + * @public + */ + setCache : function(cacheStatus){ + if(!this.dynContentObj){ + try{ + this.dynContentObj = new DHTMLSuite.dynamicContent(); // Creating dynamic content object if it doesn't already exist. + }catch(e){ + alert('You need to include dhtmlSuite-dynamicContent.js'); + } + } + this.dynContentObj.setCache(cacheStatus); // Calling the DHTMLSuite_dynamicContent setCache + + } + // }}} + , + // {{{ display() + /** + * Display the modal dialog box + * + * + * @public + */ + display : function(){ + var ind = this.objectIndex; + + if(!this.divs_transparentDiv){ + DHTMLSuite.commonObj.loadCSS(this.layoutCss); + this.__createDivElements(); + } + this.__resizeAndPositionDivElements(); + // Redisplaying divs + if(this.isModal){ + this.divs_transparentDiv.style.display='block'; + }else{ + this.divs_transparentDiv.style.display='none'; + } + this.divs_content.style.display='block'; + this.divs_shadow.style.display='block'; + + if(this.iframeEl){ + setTimeout('DHTMLSuite.variableStorage.arrayDSObjects[' + ind + '].iframeEl.style.display="block"',150); + } + + this.__resizeAndPositionDivElements(); + + /* Call the __resizeAndPositionDivElements method twice in case the css file has changed. The first execution of this method may not catch these changes */ + window.refToThisModalBoxObj = this; + setTimeout('window.refToThisModalBoxObj.__resizeAndPositionDivElements()',100); + + this.__addHTMLContent(); // Calling method which inserts content into the message div. + } + // }}} + , + // {{{ () + /** + * Display the modal dialog box + * + * + * @public + */ + setShadowDivVisible : function(visible){ + this.shadowDivVisible = visible; + } + // }}} + , + // {{{ close() + /** + * Close the modal dialog box + * + * + * @public + */ + close : function(){ + document.documentElement.style.overflow = ''; // Setting the CSS overflow attribute of the tag back to default. + /* Hiding divs */ + this.divs_transparentDiv.style.display='none'; + this.divs_content.style.display='none'; + this.divs_shadow.style.display='none'; + if(this.iframeEl)this.iframeEl.style.display='none'; + + } + // }}} + , + // {{{ __clearProperties() + /** + * Clear content properties + * + * + * @private + */ + __clearProperties : function(){ + if(this.domRef)DHTMLSuite.discardElement(this.domRef); + this.domRef = null; + this.url = false; + this.htmlOfModalMessage = false; + } + // }}} + , + // {{{ __createDivElements() + /** + * Create the divs for the modal dialog box + * + * + * @private + */ + __createDivElements : function(){ + // Creating transparent div + this.divs_transparentDiv = document.createElement('DIV'); + this.divs_transparentDiv.className='DHTMLSuite_modalDialog_transparentDivs'; + this.divs_transparentDiv.style.left = '0px'; + this.divs_transparentDiv.style.top = '0px'; + this.divs_transparentDiv.id='transparentDiv'; + document.body.appendChild(this.divs_transparentDiv); + // Creating content div + if(!document.getElementById('DHTMLSuite_modalBox_contentDiv')){ + this.divs_content = document.createElement('DIV'); + this.divs_content.className = 'DHTMLSuite_modalDialog_contentDiv'; + this.divs_content.id = 'DHTMLSuite_modalBox_contentDiv'; + document.body.appendChild(this.divs_content); + }else{ + this.divs_content = document.getElementById('DHTMLSuite_modalBox_contentDiv'); + } + // Creating shadow div + this.divs_shadow = document.createElement('DIV'); + this.divs_shadow.className = 'DHTMLSuite_modalDialog_contentDiv_shadow'; + document.body.appendChild(this.divs_shadow); + + if(DHTMLSuite.clientInfoObj.isMSIE){ + this.iframeEl = document.createElement(''; + this.formRef.method = this.method; + this.formRef.action = this.action; + this.formRef.target = this.iframeName; + if(!this.formRef.enctype)this.formRef.enctype = 'multipart/form-data'; + + } + // }}} + , + // {{{ __getIframeResponse() + /** + * Form has been submitted to iframe - move content from iframe + * + * @private + */ + __getIframeResponse : function(){ + if(this.responseEl){ + if(this.responseFile){ + if(!this.responseEl.id)this.responseEl.id = 'DHTMLSuite_formResponse' + DHTMLSuite.getUniqueId(); + var dynContent = new DHTMLSuite.dynamicContent(); + dynContent.loadContent(this.responseEl.id,this.responseFile); + }else{ + this.responseEl.innerHTML = self.frames[this.iframeName].document.body.innerHTML; + DHTMLSuite.commonObj.__evaluateJs(this.responseEl); + DHTMLSuite.commonObj.__evaluateCss(this.responseEl); + } + } + this.coverDiv.style.display='none'; + this.__handleCallback('onComplete'); + } + // }}} + , + // {{{ __positionCoverDiv() + /** + * Position cover div + * + * @private + */ + __positionCoverDiv : function(){ + if(!this.responseEl)return; + try{ + var st = this.coverDiv.style; + st.left = DHTMLSuite.commonObj.getLeftPos(this.responseEl) + 'px'; + st.top = DHTMLSuite.commonObj.getTopPos(this.responseEl) + 'px'; + st.width = this.responseEl.offsetWidth + 'px'; + st.height = this.responseEl.offsetHeight + 'px'; + st.display='block'; + }catch(e){ + } + } + // }}} + , + // {{{ __createCoverDiv() + /** + * Submits the form + * + * @private + */ + __createCoverDiv : function(){ + if(this.coverDiv)return; + this.coverDiv = document.createElement('DIV'); + var el = this.coverDiv; + el.style.overflow='hidden'; + el.style.zIndex = 1000; + el.style.position = 'absolute'; + + document.body.appendChild(el); + + var innerDiv = document.createElement('DIV'); + innerDiv.style.width='105%'; + innerDiv.style.height='105%'; + innerDiv.className = 'DHTMLSuite_formCoverDiv'; + innerDiv.style.opacity = '0.2'; + innerDiv.style.filter = 'alpha(opacity=20)'; + el.appendChild(innerDiv); + + var ajaxLoad = document.createElement('DIV'); + ajaxLoad.className = 'DHTMLSuite_formCoverDiv_ajaxLoader'; + el.appendChild(ajaxLoad); + } + // }}} + , + // {{{ __createSackObject() + /** + * Create new sack object + * + * @private + */ + __createSackObject : function(ajaxIndex){ + var ind = this.objectIndex; + this.sackObj[ajaxIndex] = new sack(); + this.sackObj[ajaxIndex].requestFile = this.action; + this.sackObj[ajaxIndex].method = this.method; + this.sackObj[ajaxIndex].onCompletion = function(){ DHTMLSuite.variableStorage.arrayDSObjects[ind].__getResponse(ajaxIndex); } + } + // }}} + , + // {{{ __getResponse() + /** + * Get response from ajax + * + * @private + */ + __getResponse : function(ajaxIndex){ + + if(this.responseEl){ + if(this.responseFile){ + if(!this.responseEl.id)this.responseEl.id = 'DHTMLSuite_formResponse' + DHTMLSuite.getUniqueId(); + var dynContent = new DHTMLSuite.dynamicContent(); + dynContent.loadContent(this.responseEl.id,this.responseFile); + }else{ + this.responseEl.innerHTML = this.sackObj[ajaxIndex].response; + DHTMLSuite.commonObj.__evaluateJs(this.responseEl); + DHTMLSuite.commonObj.__evaluateCss(this.responseEl); + } + } + + this.coverDiv.style.display='none'; + this.sackObj[ajaxIndex] = null; + this.__handleCallback('onComplete'); + } + // }}} + , + // {{{ __populateSack() + /** + * Populate sack object with form data + * @param ajaxIndex - index of current sack object + * + * @private + */ + __populateSack : function(ajaxIndex){ + var els = this.formUtil.getValuesAsArray(this.formRef); + for(var prop in els){ + if(DHTMLSuite.commonObj.isArray(els[prop])){ + for(var no=0;no=0){ // The name of the form field is already indicating an array + name = prop.replace('[','[' + no); + } + this.sackObj[ajaxIndex].setVar(name,els[prop][no]); + } + }else{ + this.sackObj[ajaxIndex].setVar(prop,els[prop]); + } + } + } + // }}} + , + // {{{ __setInitProperties() + /** + * Fill object with data sent to the constructor + * @param Array props - Associative Array("Object") of properties + * + * @private + */ + __setInitProperties : function(props){ + if(props.formRef)this.formRef = DHTMLSuite.commonObj.getEl(props.formRef); + if(props.method)this.method = props.method; + if(props.responseEl)this.responseEl = DHTMLSuite.commonObj.getEl(props.responseEl); + if(props.action)this.action = props.action; + if(props.responseFile)this.responseFile = props.responseFile; + if(props.callbackOnComplete)this.callbackOnComplete = props.callbackOnComplete; + if(!this.action)this.action = this.formRef.action; + if(!this.method)this.method = this.formRef.method; + } + // }}} + , + // {{{ __handleCallback() + /** + * Execute callback + * @param String action - Which callback action + * + * @private + */ + __handleCallback : function(action){ + var callbackString = ''; + switch(action){ + case "onComplete": + callbackString = this.callbackOnComplete; + break; + + } + if(callbackString){ + if(callbackString.indexOf('(')==-1)callbackString = callbackString + '("' + this.formRef.name + '")'; + eval(callbackString); + } + + } +} + +/*[FILE_START:dhtmlSuite-autoComplete.js] */ +/************************************************************************************************************ +* DHTML auto complete script +* +* Created: Jun, 06th, 2007 +* @module coder: Batur Orkun (batur@bilkent.edu.tr, http://www.xdhtml.com) +* +* @class Purpose of class: this script shows you a list of options based on what you type into a text input. + Example: Type in "A" and Ajax will get you a list of all contries starting with "A". +* +* Css files used by this script: auto-complete.css +* +* Demos of this class: demo-auto-complete.html +* +* Update log: +* +************************************************************************************************************/ + +/** +* @constructor +* @class Purpose of class: this script shows you a list of options based on what you type into a text input. +* @version 0.1 +* @author Alf Magne Kalleland & Batur Orkun +* (www.dhtmlgoodies.com) +*/ + +DHTMLSuite.autoComplete=function(){ + // definations + var layoutCss; + var ajaxBox_offsetX; + var ajaxBox_offsetY; + var minimumLettersBeforeLookup; // Number of letters entered before a lookup is performed. + + var ajax_list_currentLetters; + var ajax_list_cachedLists + var ajax_optionDiv; + var ajax_list_MSIE; + var ajax_list_activeItem; + var ajax_list_objects; + var ajax_list_activeInput; + var ajax_list_activeItem; + var ajax_list_optionDivFirstItem + var ajax_optionDiv; + var ajax_optionDiv_iframe; + + // set values + this.layoutCss='auto-complete.css'; + this.ajaxBox_offsetX = 0; + this.ajaxBox_offsetY = 0; + this.ajax_list_currentLetters = new Array(); + this.ajax_list_cachedLists = new Array(); + this.ajax_optionDiv = false; + this.ajax_list_MSIE = false; + if (navigator.userAgent.indexOf('MSIE')>=0 && navigator.userAgent.indexOf('Opera')<0) + this.ajax_list_MSIE=true; + this.ajax_list_activeItem; + this.ajax_list_objects = new Array(); + this.ajax_list_activeInput = false; + this.ajax_list_activeItem; + this.ajax_list_optionDivFirstItem = false; + this.ajax_optionDiv = false; + this.ajax_optionDiv_iframe = false; + + var ajax_list_MSIE = false; + if(navigator.userAgent.indexOf('MSIE')>=0 && navigator.userAgent.indexOf('Opera')<0) ajax_list_MSIE=true; + + this.minimumLettersBeforeLookup = 1; + + // check modules + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); + // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + // load object to variableStorage + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length;; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; + document.body.setAttribute("objectIndex",this.objectIndex); // set attribute to body for keyNavigation + + DHTMLSuite.commonObj.loadCSS(this.layoutCss); // load css + +} + +DHTMLSuite.autoComplete.prototype={ + + // {{{ add(inputObjId,externalFile) + /** + * add auto complete functionality for input object + * + * @param Number inputObjId - input object id + * @param String - cgi url + * + * @public + */ + add:function(inputObjId,externalFile){ + var refObject = DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex]; + eval("document.getElementById('"+inputObjId+"').onkeyup = function(e) { refObject.__showOptions(e,'"+ inputObjId +"','"+ externalFile +"') };"); + DHTMLSuite.commonObj.__addEventEl(document.getElementById(inputObjId)); + } + // }}} + , + // {{{ setLayoutCss(newCssFileName) + /** + * Set new CSS file name + * + * @param String newCssFileName-name of new css file. Should be called before any tooltips are displayed on the screen. + * + *@public + */ + setLayoutCss:function(newCssFileName){ + this.layoutCss=newCssFileName; + } + // }}} + , + // {{{ __showOptions(inputObj,externalFile,e) + /** + * show Options + * + * @param Object inputObj - input object + * @param String externalFile - cgi url + * @param Object e - error handling + * + *@private + */ + __showOptions:function(e, inputObjId,externalFile){ + var inputObj = document.getElementById(inputObjId); // input object + var ind = this.objectIndex; // class object index + + if(document.all)e = event; + if(e.keyCode==13 || e.keyCode==9)return; + if(this.ajax_list_currentLetters[inputObj.name]==inputObj.value) return; + if(!this.ajax_list_cachedLists[inputObj.id]) this.ajax_list_cachedLists[inputObj.id] = new Array(); + + this.ajax_list_currentLetters[inputObj.name] = inputObj.value; + if(!this.ajax_optionDiv){ + this.ajax_optionDiv = document.createElement('DIV'); + this.ajax_optionDiv.id = 'ajax_listOfOptions'; + document.body.appendChild(this.ajax_optionDiv); + + if(this.ajax_list_MSIE){ + this.ajax_optionDiv_iframe = document.createElement('IFRAME'); + this.ajax_optionDiv_iframe.border='0'; + this.ajax_optionDiv_iframe.style.width = this.ajax_optionDiv.clientWidth + 'px'; + this.ajax_optionDiv_iframe.style.height = this.ajax_optionDiv.clientHeight + 'px'; + this.ajax_optionDiv_iframe.id = 'ajax_listOfOptions_iframe'; + + document.body.appendChild(this.ajax_optionDiv_iframe); + } + + var allInputs = document.getElementsByTagName('INPUT'); + for(var no=0;no this.ajax_optionDiv.offsetHeight){ + this.ajax_optionDiv.scrollTop = this.ajax_list_activeItem.offsetTop - this.ajax_optionDiv.offsetHeight + this.ajax_list_activeItem.offsetHeight + 2 ; + } + if(this.ajax_list_activeItem.offsetTop < this.ajax_optionDiv.scrollTop){ + this.ajax_optionDiv.scrollTop = 0; + } + } + } + // }}} + , + // {{{ __ajaxOptionResize(inputObj) + /** + * rollover effect for options + * + * @param object item - + * @param bollean fromKeyBoard - + * + *@private + */ + __ajaxOptionResize:function(inputObj){ + this.ajax_optionDiv.style.top = (this.__ajaxGetTopPos(inputObj) + inputObj.offsetHeight + this.ajaxBox_offsetY) + 'px'; + this.ajax_optionDiv.style.left = (this.__ajaxGetLeftPos(inputObj) + this.ajaxBox_offsetX) + 'px'; + if(this.ajax_optionDiv_iframe){ + this.ajax_optionDiv_iframe.style.left = this.ajax_optionDiv.style.left; + this.ajax_optionDiv_iframe.style.top = this.ajax_optionDiv.style.top; + } + + } + // }}} + , + // {{{ __ajaxGetTopPos(inputObj) + /** + * find top position of div including options + * + * @param object inputObj - input object for using auto complete + * + *@private + */ + __ajaxGetTopPos:function(inputObj){ + var returnValue = inputObj.offsetTop; + while((inputObj = inputObj.offsetParent) != null){ + returnValue += inputObj.offsetTop; + } + return returnValue; + } + // }}} + , + // {{{ __ajaxGetLeftPos(inputObj) + /** + * find left position of div including options + * + * @param object inputObj - input object for using auto complete + * + *@private + */ + __ajaxGetLeftPos:function(inputObj){ + var returnValue = inputObj.offsetLeft; + while((inputObj = inputObj.offsetParent) != null)returnValue += inputObj.offsetLeft; + + return returnValue; + } + // }}} + , + // {{{ __ajaxOptionListShowContent(ajaxIndex,inputObj) + /** + * call build options function and show content + * + * @param number ajaxIndex + * @param object inputObj - input object + * + *@private + */ + __ajaxOptionListShowContent:function(ajaxIndex,inputObj){ + var letters = inputObj.value; + var content = this.ajax_list_objects[ajaxIndex].response; + var elements = content.split('|'); + this.ajax_list_cachedLists[inputObj.id][letters.toLowerCase()] = elements; + this.__ajaxOptionListBuildList(letters,inputObj.id); + + } + // }}} + , + // {{{ __ajaxOptionListBuildList(letters,inputObjId) + /** + * build options list + * + * @param string letters : input value + * @param string inputObjId + * + *@private + */ + __ajaxOptionListBuildList:function(letters,inputObjId){ + var ind = this.objectIndex; + + //alert(inputObjId); + + this.ajax_optionDiv.innerHTML = ''; + this.ajax_list_activeItem = false; + if(this.ajax_list_cachedLists[inputObjId][letters.toLowerCase()].length<=1){ + this.__ajaxOptionsHide(); + return; + } + + this.ajax_list_optionDivFirstItem = false; + var optionsAdded = false; + for(var no=0;noDemo) +* @version 0.1 +* @author Alf Magne Kalleland & Batur Orkun +* (www.dhtmlgoodies.com) +*/ + +DHTMLSuite.chainedSelect=function(){ + + var targetSels; + var sourceSels; + var urls; + + var waitMessage; + var layoutCss; + var objectIndex; + + this.targetSels = new Array(); + this.sourceSels = new Array(); + this.urls = new Array(); + + try{ + if(!standardObjectsCreated)DHTMLSuite.createStandardObjects(); + // This line starts all the init methods + }catch(e){ + alert('You need to include the dhtmlSuite-common.js file'); + } + + this.objectIndex = DHTMLSuite.variableStorage.arrayDSObjects.length;; + DHTMLSuite.variableStorage.arrayDSObjects[this.objectIndex] = this; +} + +DHTMLSuite.chainedSelect.prototype={ + // {{{ init() + /** + * Initializes the script + * + * + * @public + */ + init:function() + { + var ind = this.objectIndex; + for(index=0; index1)targetObj.options[targetObj.options.length] = new Option(option_array[0].trim(), option_array[1].trim()); + } + + } +} diff --git a/ext/dhtml-suite-for-applications/licenses/dhtmlsuite-for-applications.txt b/ext/dhtml-suite-for-applications/licenses/dhtmlsuite-for-applications.txt index 02a8b59..e1504da 100755 --- a/ext/dhtml-suite-for-applications/licenses/dhtmlsuite-for-applications.txt +++ b/ext/dhtml-suite-for-applications/licenses/dhtmlsuite-for-applications.txt @@ -1,505 +1,505 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - - + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + + diff --git a/ext/dhtml-suite-for-applications/licenses/sack-licence.html b/ext/dhtml-suite-for-applications/licenses/sack-licence.html index 685f56f..b2c2375 100755 --- a/ext/dhtml-suite-for-applications/licenses/sack-licence.html +++ b/ext/dhtml-suite-for-applications/licenses/sack-licence.html @@ -1,28 +1,28 @@ - - - - Simple AJAX Code-Kit (SACK) Licence - - - - - - -

      Note: This is a modified version of the X11 Licence (commonly known as the MIT licence). The modifications relate to including not only the copyright notice, as per the original X11, but also the authors URL. This is a trivial modification, and does not affect any other part of the licence.

      - -

      COPYRIGHT AND PERMISSION NOTICE for Simple AJAX Code Kit (SACK).

      - -

      Copyright © 2005 Gregory Wild-Smith
      -Authors Website: http://www.twilightuniverse.com/

      - -

      All rights reserved.

      - -

      Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s), authors website url, and this permission notice appear in all copies of the Software and that the above copyright notice(s), authors url, and this permission notice appear in supporting documentation.

      - -

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

      - -

      Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.

      - + + + + Simple AJAX Code-Kit (SACK) Licence + + + + + + +

      Note: This is a modified version of the X11 Licence (commonly known as the MIT licence). The modifications relate to including not only the copyright notice, as per the original X11, but also the authors URL. This is a trivial modification, and does not affect any other part of the licence.

      + +

      COPYRIGHT AND PERMISSION NOTICE for Simple AJAX Code Kit (SACK).

      + +

      Copyright © 2005 Gregory Wild-Smith
      +Authors Website: http://www.twilightuniverse.com/

      + +

      All rights reserved.

      + +

      Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, provided that the above copyright notice(s), authors website url, and this permission notice appear in all copies of the Software and that the above copyright notice(s), authors url, and this permission notice appear in supporting documentation.

      + +

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

      + +

      Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder.

      + \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/auto-complete.css b/ext/dhtml-suite-for-applications/themes/tmw/css/auto-complete.css index 05b988f..bc0ca5a 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/auto-complete.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/auto-complete.css @@ -1,32 +1,32 @@ - - -/* Big box with list of options */ -#ajax_listOfOptions{ - position:absolute; /* Never change this one */ - width:175px; /* Width of box */ - height:250px; /* Height of box */ - overflow:auto; /* Scrolling features */ - border:1px solid #317082; /* Dark green border */ - background-color:#FFF; /* White background color */ - text-align:left; - font-size:0.9em; - z-index:100; -} -#ajax_listOfOptions div{ /* General rule for both .optionDiv and .optionDivSelected */ - margin:1px; - padding:1px; - cursor:pointer; - font-size:0.9em; -} -#ajax_listOfOptions .optionDiv{ /* Div for each item in list */ - -} -#ajax_listOfOptions .optionDivSelected{ /* Selected item in the list */ - background-color:#317082; - color:#FFF; -} -#ajax_listOfOptions_iframe{ - background-color:#F00; - position:absolute; - z-index:5; -} + + +/* Big box with list of options */ +#ajax_listOfOptions{ + position:absolute; /* Never change this one */ + width:175px; /* Width of box */ + height:250px; /* Height of box */ + overflow:auto; /* Scrolling features */ + border:1px solid #317082; /* Dark green border */ + background-color:#FFF; /* White background color */ + text-align:left; + font-size:0.9em; + z-index:100; +} +#ajax_listOfOptions div{ /* General rule for both .optionDiv and .optionDivSelected */ + margin:1px; + padding:1px; + cursor:pointer; + font-size:0.9em; +} +#ajax_listOfOptions .optionDiv{ /* Div for each item in list */ + +} +#ajax_listOfOptions .optionDivSelected{ /* Selected item in the list */ + background-color:#317082; + color:#FFF; +} +#ajax_listOfOptions_iframe{ + background-color:#F00; + position:absolute; + z-index:5; +} diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/calendar.css b/ext/dhtml-suite-for-applications/themes/tmw/css/calendar.css index c16cf32..109646f 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/calendar.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/calendar.css @@ -1,338 +1,338 @@ -.DHTMLSuite_calendar{ /* Main div for the calendar */ - border:1px solid #444444; - background-color:#FFF; - width:220px; - position:relative; - overflow:hidden; - -} -.DHTMLSuite_calendarContent{ /* Sub div inside DHTMLSuite_calendar - this is the div where content is added */ - position:relative; /* IMPORTANT - This must always be like this in order to make it possible to position sub elements correctly, especially the iframe */ - z-index:10; /* IMPORTANT - This must always be like this in order to make it possible to position sub elements correctly, especially the iframe */ - background-color:#FFF; - font-family: Trebuchet MS, Lucida Sans Unicode, Arial, sans-serif; -} - - -/******************* - - START CSS FOR THE HEADER ROW - WHERE YOU SEE MONTH AND YEAR - -********************/ -.DHTMLSuite_calendar .DHTMLSuite_calendarHeading{ /* Heading of calendar, where you see the month and year */ - background-image:url(../images/calendar/calendar_heading.png); - background-repeat:repeat-x; - height:21px; - border-bottom:1px solid #444444; -} -.DHTMLSuite_calendarHeadingTxt{ /* Inner div in the heading */ - padding:1px; - text-align:center; - font-size:13px; - color:#FFF; -} - -.DHTMLSuite_calendarCloseButton{ /* Close button at the top right corner of the calendar */ - background-image:url(../images/calendar/calendar-close.gif); - background-repeat:no-repeat; - width:13px; - height:13px; - position:absolute; - right:3px; - top:3px; - padding:1px; - background-position:center center; - cursor:pointer; -} - -.DHTMLSuite_calendarHeaderMonthAndYear{ /* Div elements for year and month in the heading */ - padding:1px; - padding-right:2px; - padding-left:2px; - cursor:pointer; - line-height:17px; - -} -.DHTMLSuite_calendarHeaderMonthAndYearOver{ /* Mouse over effect - month and year in the heading */ - background-color:#444; - border:1px solid #555; - padding:0px; - padding-left:1px; - padding-right:1px; -} - - -/******************* - - START CSS FOR THE TIME BAR - THE DIV WHERE YOU SEE "Time: " and the hour and minute - -********************/ - -.DHTMLSuite_calendar_timeBar{ /* Time bar - where users can select hour and minutes */ - background-color:#555; - height:21px; - border-top:1px solid #444444; - text-align:center; - position:relative; - color:#FFF; -} -.DHTMLSuite_calendar_timeBarHourAndMinute{ /* General rules for the displayed hours and minutes - the ones you can click on the bring out the drop down boxes */ - padding:1px; - padding-left:2px; - padding-right:2px; - margin-right:2px; - cursor:pointer; -} -.DHTMLSuite_calendarTimeBarHourAndMinuteOver{ /* Mouse over effect for the hour and minute displayed in the time bar */ - background-color:#444; - border:1px solid #555; - padding:0px; - padding-left:1px; - padding-right:1px; -} -.DHTMLSuite_calendarTimeBarTimeString{ /* String "Time:" */ - position:absolute; - left:2px; - top:2px; -} - -/******************* - - START CSS FOR THE NAVIGATION BAR - THE DIV WITH THE LEFT AND RIGHT ARROWS - -********************/ - -.DHTMLSuite_calendar_navigationBar{ /* Navigation bar below the heading */ - background-color:#555; - height:17px; - border-bottom:1px solid #444444; - position:relative; -} -.DHTMLSuite_calendar_navigationBarToday{ /* Div for the string "Today" in the navigation bar */ - text-align:center; - color:#FFF; -} -.DHTMLSuite_calendar_navigationBarToday span{ /* The "Today" string inside the navigation bar */ - cursor:pointer; -} -.DHTMLSuite_calendar_btnNextYear,.DHTMLSuite_calendar_btnPreviousYear,.DHTMLSuite_calendar_btnNextMonth,.DHTMLSuite_calendar_btnPreviousMonth{ /* Buttons - previous/next month and year */ - position:absolute; - background-repeat:no-repeat; - background-position:center center; - width:13px; - height:13px; - padding:1px; - top:1px; -} - -.DHTMLSuite_calendar_btnNextYear{ /* Next year button */ - background-image:url(../images/calendar/calendar-next-year.gif); - right:2px; -} -.DHTMLSuite_calendar_btnPreviousYear{ /* Previous year button */ - background-image:url(../images/calendar/calendar-previous-year.gif); - left:2px; -} -.DHTMLSuite_calendar_btnNextMonth{ /* Next month button */ - background-image:url(../images/calendar/calendar-next-month.gif); - right:18px; -} -.DHTMLSuite_calendar_btnPreviousMonth{ /* Previous month button */ - background-image:url(../images/calendar/calendar-previous-month.gif); - left:18px; -} - -/******************* - - START CSS FOR THE MAIN DIV CONTAINING ALL THE DAYS WITHIN A MONTH AND HEADINGS (weeks, days(Mon-Sun) etc.) - -********************/ - - -.DHTMLSuite_calendar_monthView{ /* Main div element for the days in a month */ - - -} - -.DHTMLSuite_calendar_monthView_headerCell{ /* Main div element for the days in a month */ - background-color:#FFF; - border-bottom:1px solid #444444; -} - -.DHTMLSuite_calendar_monthView_firstColumn{ /* First column - the week column */ - background-color:#555; - border-right:1px solid #444444; - text-align:left; - color:#FFF; -} - -.DHTMLSuite_calendar_monthView td{ /* Default css for all the cells inside the calendar, i.e. week heading, label for the days, and the days */ - text-align:center; - cursor:default; -} -.DHTMLSuite_calendar_monthView_headerSunday{ /* Sunday in the header */ - color:red; - border-bottom:1px solid #444444; -} -.DHTMLSuite_calendar_monthView_daysInOtherMonths{ /* Days in previous or next month, i.e. before start of current displayed month or after days in the currently displayed month */ - color:#999; -} -.DHTMLSuite_calendar_monthView_daysInThisMonth{ /* Layout - ordinary days(mon-sat) in this month */ - -} -.DHTMLSuite_calendar_monthView_sundayInThisMonth{ /* Layout - sundays in current displayed month */ - color:red; -} -.DHTMLSuite_calendar_monthView_initialDate{ /* Inital set date, example: the date in an input field which you are populating with the calendar */ - background-color:#444444; - color:white; -} -.DHTMLSuite_calendar_monthView_invalidDate{ /* Inital set date, example: the date in an input field which you are populating with the calendar */ - color:#AAA; -} -.DHTMLSuite_calendar_monthView_currentDate{ /* Date of today */ - background-color:#E2E2E2; -} -/*************************************************** -* -* START CSS - DROP DOWN BOXES -* -* -***************************************************/ - -/*** MINUTES ***/ -.DHTMLSuite_calendar_minuteDropDown{ /* Drop down box for minutes */ - background-color:#555; - border:1px solid #444444; - width:23px; - padding:1px; - font-size:12px; - text-align:center; - /* You shouldn't change these 3 options */ - position:absolute; - z-index:152000; - cursor:pointer; - -} -.DHTMLSuite_calendar_minuteDropDownCurrentMinute{ /* Minute in drop down when it's equal to current minute of the display, i.e. the minute you see where you click on the drop down */ - color:red; -} -.DHTMLSuite_calendar_dropDownAMinute{ - color:#FFF; -} -.DHTMLSuite_calendar_dropdownAMinuteOver{ - background-color:#E2E2E2; - color:#222; -} - -/*** HOURS ***/ -.DHTMLSuite_calendar_hourDropDown{ /* Drop down box for hours */ - background-color:#555; - border:1px solid #444444; - width:23px; - position:absolute; - z-index:152000; - padding:1px; - cursor:pointer; - font-size:12px; - text-align:center; -} -.DHTMLSuite_calendar_dropDownAnHour{ - color:#FFF; -} -.DHTMLSuite_calendar_dropdownAnHourOver{ - background-color:#E2E2E2; - color:#222; -} -.DHTMLSuite_calendar_hourDropDownCurrentHour{ - color:red; -} - -/*** MONTHS ***/ -.DHTMLSuite_calendar_monthDropDown{ - background-color:#555; - border:1px solid #444444; - width:70px; - position:absolute; - z-index:152000; - cursor:pointer; - padding:1px; - font-size:12px; -} -.DHTMLSuite_calendar_dropDownAMonth{ - color:#FFF; -} -.DHTMLSuite_calendar_dropdownAMonthOver{ - background-color:#E2E2E2; - color:#000; -} -.DHTMLSuite_calendar_yearDropDownCurrentMonth{ - color:red; - -} - -/***** YEAR ****/ -.DHTMLSuite_calendar_yearDropDown{ - background-color:#555; - border:1px solid #444444; - width:30px; - position:absolute; - z-index:152000; - cursor:pointer; - padding:1px; - font-size:12px; - text-align:center; -} -.DHTMLSuite_calendar_dropDownAYear{ - color:#FFF; - -} -.DHTMLSuite_calendar_dropdownAYearOver{ - background-color:#E2E2E2; - color:#000; -} -.DHTMLSuite_calendar_yearDropDownCurrentYear{ /* Current year */ - color:red; -} - - - -/* UP AND DOWN ARROWS INSIDE DROP DOWNS **/ -.DHTMLSuite_calendar_dropDown_arrowUp{ /* Drop down - moving to previous year */ - background-image:url(../images/calendar/calendar-dropdown-up.gif); - background-repeat:no-repeat; - background-position:center center; - height:8px; -} - -.DHTMLSuite_calendar_dropDown_arrowDown{ /* Drop down - moving to previous year */ - background-image:url(../images/calendar/calendar-dropdown-down.gif); - background-repeat:no-repeat; - background-position:center center; - height:8px; -} -.DHTMLSuite_calendarDropDown_dropDownArrowOver{ - background-color:#BBB; -} - - - - -/* IT'S IMPORTANT TO HAVE THIS CSS RULE AT THE BOTTOM IN ORDER TO MAKE THE PADDING OVERRIDE PADDING OF OTHER ELEMENTS */ -.DHTMLSuite_calendarButtonOver{ /* Mouse over effect for the close button */ - background-color:#444; - border:1px solid #555; - padding:0px; /* The sum border+padding of this element should be the same as border+padding of .DHTMLSuite_calendarCloseButton */ -} -.DHTMLSuite_calendarDayOver{ /* Mouse over effect - days in the calendar, i.e. days in current displayed month */ - background-color:#555; - color:#E2E2E2; -} - -/* YOU SHOULD NEVER MODIFY THIS ONE */ -.DHTMLSuite_calendar_iframe{ /* Iframe used to cover select boxes below in older IE browsers(version 6 and prior) */ - position:absolute; - top:1px; - left:1px; - z-index:1; -} +.DHTMLSuite_calendar{ /* Main div for the calendar */ + border:1px solid #444444; + background-color:#FFF; + width:220px; + position:relative; + overflow:hidden; + +} +.DHTMLSuite_calendarContent{ /* Sub div inside DHTMLSuite_calendar - this is the div where content is added */ + position:relative; /* IMPORTANT - This must always be like this in order to make it possible to position sub elements correctly, especially the iframe */ + z-index:10; /* IMPORTANT - This must always be like this in order to make it possible to position sub elements correctly, especially the iframe */ + background-color:#FFF; + font-family: Trebuchet MS, Lucida Sans Unicode, Arial, sans-serif; +} + + +/******************* + + START CSS FOR THE HEADER ROW - WHERE YOU SEE MONTH AND YEAR + +********************/ +.DHTMLSuite_calendar .DHTMLSuite_calendarHeading{ /* Heading of calendar, where you see the month and year */ + background-image:url(../images/calendar/calendar_heading.png); + background-repeat:repeat-x; + height:21px; + border-bottom:1px solid #444444; +} +.DHTMLSuite_calendarHeadingTxt{ /* Inner div in the heading */ + padding:1px; + text-align:center; + font-size:13px; + color:#FFF; +} + +.DHTMLSuite_calendarCloseButton{ /* Close button at the top right corner of the calendar */ + background-image:url(../images/calendar/calendar-close.gif); + background-repeat:no-repeat; + width:13px; + height:13px; + position:absolute; + right:3px; + top:3px; + padding:1px; + background-position:center center; + cursor:pointer; +} + +.DHTMLSuite_calendarHeaderMonthAndYear{ /* Div elements for year and month in the heading */ + padding:1px; + padding-right:2px; + padding-left:2px; + cursor:pointer; + line-height:17px; + +} +.DHTMLSuite_calendarHeaderMonthAndYearOver{ /* Mouse over effect - month and year in the heading */ + background-color:#444; + border:1px solid #555; + padding:0px; + padding-left:1px; + padding-right:1px; +} + + +/******************* + + START CSS FOR THE TIME BAR - THE DIV WHERE YOU SEE "Time: " and the hour and minute + +********************/ + +.DHTMLSuite_calendar_timeBar{ /* Time bar - where users can select hour and minutes */ + background-color:#555; + height:21px; + border-top:1px solid #444444; + text-align:center; + position:relative; + color:#FFF; +} +.DHTMLSuite_calendar_timeBarHourAndMinute{ /* General rules for the displayed hours and minutes - the ones you can click on the bring out the drop down boxes */ + padding:1px; + padding-left:2px; + padding-right:2px; + margin-right:2px; + cursor:pointer; +} +.DHTMLSuite_calendarTimeBarHourAndMinuteOver{ /* Mouse over effect for the hour and minute displayed in the time bar */ + background-color:#444; + border:1px solid #555; + padding:0px; + padding-left:1px; + padding-right:1px; +} +.DHTMLSuite_calendarTimeBarTimeString{ /* String "Time:" */ + position:absolute; + left:2px; + top:2px; +} + +/******************* + + START CSS FOR THE NAVIGATION BAR - THE DIV WITH THE LEFT AND RIGHT ARROWS + +********************/ + +.DHTMLSuite_calendar_navigationBar{ /* Navigation bar below the heading */ + background-color:#555; + height:17px; + border-bottom:1px solid #444444; + position:relative; +} +.DHTMLSuite_calendar_navigationBarToday{ /* Div for the string "Today" in the navigation bar */ + text-align:center; + color:#FFF; +} +.DHTMLSuite_calendar_navigationBarToday span{ /* The "Today" string inside the navigation bar */ + cursor:pointer; +} +.DHTMLSuite_calendar_btnNextYear,.DHTMLSuite_calendar_btnPreviousYear,.DHTMLSuite_calendar_btnNextMonth,.DHTMLSuite_calendar_btnPreviousMonth{ /* Buttons - previous/next month and year */ + position:absolute; + background-repeat:no-repeat; + background-position:center center; + width:13px; + height:13px; + padding:1px; + top:1px; +} + +.DHTMLSuite_calendar_btnNextYear{ /* Next year button */ + background-image:url(../images/calendar/calendar-next-year.gif); + right:2px; +} +.DHTMLSuite_calendar_btnPreviousYear{ /* Previous year button */ + background-image:url(../images/calendar/calendar-previous-year.gif); + left:2px; +} +.DHTMLSuite_calendar_btnNextMonth{ /* Next month button */ + background-image:url(../images/calendar/calendar-next-month.gif); + right:18px; +} +.DHTMLSuite_calendar_btnPreviousMonth{ /* Previous month button */ + background-image:url(../images/calendar/calendar-previous-month.gif); + left:18px; +} + +/******************* + + START CSS FOR THE MAIN DIV CONTAINING ALL THE DAYS WITHIN A MONTH AND HEADINGS (weeks, days(Mon-Sun) etc.) + +********************/ + + +.DHTMLSuite_calendar_monthView{ /* Main div element for the days in a month */ + + +} + +.DHTMLSuite_calendar_monthView_headerCell{ /* Main div element for the days in a month */ + background-color:#FFF; + border-bottom:1px solid #444444; +} + +.DHTMLSuite_calendar_monthView_firstColumn{ /* First column - the week column */ + background-color:#555; + border-right:1px solid #444444; + text-align:left; + color:#FFF; +} + +.DHTMLSuite_calendar_monthView td{ /* Default css for all the cells inside the calendar, i.e. week heading, label for the days, and the days */ + text-align:center; + cursor:default; +} +.DHTMLSuite_calendar_monthView_headerSunday{ /* Sunday in the header */ + color:red; + border-bottom:1px solid #444444; +} +.DHTMLSuite_calendar_monthView_daysInOtherMonths{ /* Days in previous or next month, i.e. before start of current displayed month or after days in the currently displayed month */ + color:#999; +} +.DHTMLSuite_calendar_monthView_daysInThisMonth{ /* Layout - ordinary days(mon-sat) in this month */ + +} +.DHTMLSuite_calendar_monthView_sundayInThisMonth{ /* Layout - sundays in current displayed month */ + color:red; +} +.DHTMLSuite_calendar_monthView_initialDate{ /* Inital set date, example: the date in an input field which you are populating with the calendar */ + background-color:#444444; + color:white; +} +.DHTMLSuite_calendar_monthView_invalidDate{ /* Inital set date, example: the date in an input field which you are populating with the calendar */ + color:#AAA; +} +.DHTMLSuite_calendar_monthView_currentDate{ /* Date of today */ + background-color:#E2E2E2; +} +/*************************************************** +* +* START CSS - DROP DOWN BOXES +* +* +***************************************************/ + +/*** MINUTES ***/ +.DHTMLSuite_calendar_minuteDropDown{ /* Drop down box for minutes */ + background-color:#555; + border:1px solid #444444; + width:23px; + padding:1px; + font-size:12px; + text-align:center; + /* You shouldn't change these 3 options */ + position:absolute; + z-index:152000; + cursor:pointer; + +} +.DHTMLSuite_calendar_minuteDropDownCurrentMinute{ /* Minute in drop down when it's equal to current minute of the display, i.e. the minute you see where you click on the drop down */ + color:red; +} +.DHTMLSuite_calendar_dropDownAMinute{ + color:#FFF; +} +.DHTMLSuite_calendar_dropdownAMinuteOver{ + background-color:#E2E2E2; + color:#222; +} + +/*** HOURS ***/ +.DHTMLSuite_calendar_hourDropDown{ /* Drop down box for hours */ + background-color:#555; + border:1px solid #444444; + width:23px; + position:absolute; + z-index:152000; + padding:1px; + cursor:pointer; + font-size:12px; + text-align:center; +} +.DHTMLSuite_calendar_dropDownAnHour{ + color:#FFF; +} +.DHTMLSuite_calendar_dropdownAnHourOver{ + background-color:#E2E2E2; + color:#222; +} +.DHTMLSuite_calendar_hourDropDownCurrentHour{ + color:red; +} + +/*** MONTHS ***/ +.DHTMLSuite_calendar_monthDropDown{ + background-color:#555; + border:1px solid #444444; + width:70px; + position:absolute; + z-index:152000; + cursor:pointer; + padding:1px; + font-size:12px; +} +.DHTMLSuite_calendar_dropDownAMonth{ + color:#FFF; +} +.DHTMLSuite_calendar_dropdownAMonthOver{ + background-color:#E2E2E2; + color:#000; +} +.DHTMLSuite_calendar_yearDropDownCurrentMonth{ + color:red; + +} + +/***** YEAR ****/ +.DHTMLSuite_calendar_yearDropDown{ + background-color:#555; + border:1px solid #444444; + width:30px; + position:absolute; + z-index:152000; + cursor:pointer; + padding:1px; + font-size:12px; + text-align:center; +} +.DHTMLSuite_calendar_dropDownAYear{ + color:#FFF; + +} +.DHTMLSuite_calendar_dropdownAYearOver{ + background-color:#E2E2E2; + color:#000; +} +.DHTMLSuite_calendar_yearDropDownCurrentYear{ /* Current year */ + color:red; +} + + + +/* UP AND DOWN ARROWS INSIDE DROP DOWNS **/ +.DHTMLSuite_calendar_dropDown_arrowUp{ /* Drop down - moving to previous year */ + background-image:url(../images/calendar/calendar-dropdown-up.gif); + background-repeat:no-repeat; + background-position:center center; + height:8px; +} + +.DHTMLSuite_calendar_dropDown_arrowDown{ /* Drop down - moving to previous year */ + background-image:url(../images/calendar/calendar-dropdown-down.gif); + background-repeat:no-repeat; + background-position:center center; + height:8px; +} +.DHTMLSuite_calendarDropDown_dropDownArrowOver{ + background-color:#BBB; +} + + + + +/* IT'S IMPORTANT TO HAVE THIS CSS RULE AT THE BOTTOM IN ORDER TO MAKE THE PADDING OVERRIDE PADDING OF OTHER ELEMENTS */ +.DHTMLSuite_calendarButtonOver{ /* Mouse over effect for the close button */ + background-color:#444; + border:1px solid #555; + padding:0px; /* The sum border+padding of this element should be the same as border+padding of .DHTMLSuite_calendarCloseButton */ +} +.DHTMLSuite_calendarDayOver{ /* Mouse over effect - days in the calendar, i.e. days in current displayed month */ + background-color:#555; + color:#E2E2E2; +} + +/* YOU SHOULD NEVER MODIFY THIS ONE */ +.DHTMLSuite_calendar_iframe{ /* Iframe used to cover select boxes below in older IE browsers(version 6 and prior) */ + position:absolute; + top:1px; + left:1px; + z-index:1; +} diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/color-palette.css b/ext/dhtml-suite-for-applications/themes/tmw/css/color-palette.css index b9a84d1..f6a4326 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/color-palette.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/color-palette.css @@ -1,10 +1,10 @@ -.DHTMLSuite_colorPaletteColor{ - width:12px; - height:12px; - float:left; - cursor:pointer; - border:1px solid #000; - margin:1px; -} - - +.DHTMLSuite_colorPaletteColor{ + width:12px; + height:12px; + float:left; + cursor:pointer; + border:1px solid #000; + margin:1px; +} + + diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/color-slider.css b/ext/dhtml-suite-for-applications/themes/tmw/css/color-slider.css index d9b9978..cf2b0df 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/color-slider.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/color-slider.css @@ -1,65 +1,65 @@ -.DHTMLSuite_colorSlider{ - width:380px; - height:110px; -} -.DHTMLSuite_colorSlider input{ - font-size:10px; -} - -.DHTMLSuite_colorSliderPreviewParent{ - width:50px; - float:left; -} -.DHTMLSuite_colorSliderPreview{ /* Color preview */ - width:40px; - height:60px; - margin-left:3px; - border:1px solid #000; -} - -.DHTMLSuite_colorSliderSliderParent{ /* Parent div of slider */ - width:320px; - height:60px; - float:left; -} - -.DHTMLSuite_colorSliderSliderColorRow{ - height:20px; - clear:both; -} -.DHTMLSuite_colorSliderSliderColorRow div{ - -} -.DHTMLSuite_colorSliderSliderColorRow input{ - width:28px; - -} -.DHTMLSuite_colorSliderSliderInputDiv{/* Small div which is parent of input boxes */ - float:left; - width:30px; - float:left; -} -.DHTMLSuite_colorSliderSliderLabelDiv{ /* Small div which is parent of the labels "R", "G" and "B" in front of the sliders */ - width:20px; - float:left; -} -.DHTMLSuite_colorSliderSlider{ /* Parent of the slider */ - width:247px; - float:left; - height:15px; - -} - -.DHTMLSuite_colorSliderRgbBgParent{ - margin-top:5px; - clear:both; -} - -.DHTMLSuite_colorSliderRgbBg{ - background-image:url('../images/colorPalettes/rgbColors.png'); - background-repeat:no-repeat; - width:351px; - height:20px; - position:relative; - cursor:crosshair; +.DHTMLSuite_colorSlider{ + width:380px; + height:110px; +} +.DHTMLSuite_colorSlider input{ + font-size:10px; +} + +.DHTMLSuite_colorSliderPreviewParent{ + width:50px; + float:left; +} +.DHTMLSuite_colorSliderPreview{ /* Color preview */ + width:40px; + height:60px; + margin-left:3px; + border:1px solid #000; +} + +.DHTMLSuite_colorSliderSliderParent{ /* Parent div of slider */ + width:320px; + height:60px; + float:left; +} + +.DHTMLSuite_colorSliderSliderColorRow{ + height:20px; + clear:both; +} +.DHTMLSuite_colorSliderSliderColorRow div{ + +} +.DHTMLSuite_colorSliderSliderColorRow input{ + width:28px; + +} +.DHTMLSuite_colorSliderSliderInputDiv{/* Small div which is parent of input boxes */ + float:left; + width:30px; + float:left; +} +.DHTMLSuite_colorSliderSliderLabelDiv{ /* Small div which is parent of the labels "R", "G" and "B" in front of the sliders */ + width:20px; + float:left; +} +.DHTMLSuite_colorSliderSlider{ /* Parent of the slider */ + width:247px; + float:left; + height:15px; + +} + +.DHTMLSuite_colorSliderRgbBgParent{ + margin-top:5px; + clear:both; +} + +.DHTMLSuite_colorSliderRgbBg{ + background-image:url('../images/colorPalettes/rgbColors.png'); + background-repeat:no-repeat; + width:351px; + height:20px; + position:relative; + cursor:crosshair; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/color-widget.css b/ext/dhtml-suite-for-applications/themes/tmw/css/color-widget.css index f13a6b5..9db1505 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/color-widget.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/color-widget.css @@ -1,174 +1,174 @@ - -.DHTMLSuite_colorSlider{ - margin:2px; - width:450px; - height:210px; - padding-top:10px; - padding-left:10px; - position:relative; -} - -.DHTMLSuite_colorSlider_palette_border{ - border-top:2px solid #B2B2B2; - border-left:2px solid #ACA899; - border-bottom:2px solid #FFF; - border-right:2px solid #FFF; - width:256px; - height:256px; - float:left; - margin-right:5px; -} - - - -/* Vertical hue bar/slider */ -.DHTMLSuite_colorSlider_hue{ - width:40px; - position:relative; - padding-left:10px; - float:left; -} - -.DHTMLSuite_colorSlider_hueBar_border{ - border-top:2px solid #B2B2B2; - border-left:2px solid #ACA899; - border-bottom:2px solid #FFF; - border-right:2px solid #FFF; - width:20px; - height:256px; - position:relative; - z-index:10; -} - - -.DHTMLSuite_colorSlider_hueBar{ - background-image:url('../images/colorPalettes/hueBar.png'); - height:256px; - width:20px; - background-color:red; -} -.DHTMLSuite_colorSlider_sliderHandle{ - width:41px; - height:9px; - background-image:url('../images/colorPalettes/slider-handle-left.gif'); - background-repeat:no-repeat; - position:absolute; - z-index:15; - left:1px; - top:-2px; - cursor:default; -} -.DHTMLSuite_colorSlider_sliderHandle div{ - background-image:url('../images/colorPalettes/slider-handle-right.gif'); - background-repeat:no-repeat; - background-position:top right; - height:9px; -} - -/* horizontal hue bar */ - -/* Vertical hue bar/slider */ - -.DHTMLSuite_colorSlider_hueHorizontal{ - height:40px; - width:360px; - position:relative; - padding-top:10px; - margin-top:5px; - clear:both; -} - - -.DHTMLSuite_colorSlider_hueBarHorizontal_border{ - border-top:2px solid #B2B2B2; - border-left:2px solid #ACA899; - border-bottom:2px solid #FFF; - border-right:2px solid #FFF; - width:360px; - height:20px; - position:relative; - z-index:10; -} - - -.DHTMLSuite_colorSlider_hueBarHorizontal{ - background-image:url('../images/colorPalettes/hueBar-horizontal.png'); - width:360px; - height:20px; - background-color:red; -} -.DHTMLSuite_colorSlider_sliderHandleHorizontal{ - height:41px; - width:9px; - background-image:url('../images/colorPalettes/slider-handle-down.gif'); - background-repeat:no-repeat; - position:absolute; - z-index:15; - top:1px; - left:-4px; - cursor:default; -} -.DHTMLSuite_colorSlider_sliderHandleHorizontal div{ - background-image:url('../images/colorPalettes/slider-handle-up.gif'); - background-repeat:no-repeat; - background-position:top right; - height:9px; - width:9px; - position:absolute; - bottom:0px; -} - - - -.DHTMLSuite_colorSlider_palette{ - width:256px; - height:256px; - float:left; -} - -.DHTMLSuite_colorSlider_palette_circle{ - background-image:url('../images/colorPalettes/circle-selected-black.gif'); - width:13px; - height:13px; - position:absolute; - z-index:100000; - background-position: center center; - background-repeat:no-repeat; - padding:0px; - -} -.DHTMLSuite_colorSlider_palette_circleBlack{ - background-image:url('../images/colorPalettes/circle-selected-black.gif'); -} - -.DHTMLSuite_colorSliderFormDiv{ /* Div element for the form at the right side of the hue bar */ - float:left; - width:100px; - height:256px; -} - -.DHTMLSuite_colorSlider_colorPreview{ - width:80px; - height:50px; - border-left:1px solid #B2B2B2; - border-top:1px solid #B2B2B2; - border-bottom:1px solid #FFF; - border-right:1px solid #FFF; -} - -.DHTMLSuite_colorSliderFormTable{ - font-size:12px; -} - -.DHTMLSuite_colorSliderFormTable input{ - width:30px; - font-family:arial; - font-size:11px; -} -input.DHTMLSuite_colorSlider_rgbCode{ - width:50px; -} - -img{ - behaviour:url('/pngbehavior.htc'); + +.DHTMLSuite_colorSlider{ + margin:2px; + width:450px; + height:210px; + padding-top:10px; + padding-left:10px; + position:relative; +} + +.DHTMLSuite_colorSlider_palette_border{ + border-top:2px solid #B2B2B2; + border-left:2px solid #ACA899; + border-bottom:2px solid #FFF; + border-right:2px solid #FFF; + width:256px; + height:256px; + float:left; + margin-right:5px; +} + + + +/* Vertical hue bar/slider */ +.DHTMLSuite_colorSlider_hue{ + width:40px; + position:relative; + padding-left:10px; + float:left; +} + +.DHTMLSuite_colorSlider_hueBar_border{ + border-top:2px solid #B2B2B2; + border-left:2px solid #ACA899; + border-bottom:2px solid #FFF; + border-right:2px solid #FFF; + width:20px; + height:256px; + position:relative; + z-index:10; +} + + +.DHTMLSuite_colorSlider_hueBar{ + background-image:url('../images/colorPalettes/hueBar.png'); + height:256px; + width:20px; + background-color:red; +} +.DHTMLSuite_colorSlider_sliderHandle{ + width:41px; + height:9px; + background-image:url('../images/colorPalettes/slider-handle-left.gif'); + background-repeat:no-repeat; + position:absolute; + z-index:15; + left:1px; + top:-2px; + cursor:default; +} +.DHTMLSuite_colorSlider_sliderHandle div{ + background-image:url('../images/colorPalettes/slider-handle-right.gif'); + background-repeat:no-repeat; + background-position:top right; + height:9px; +} + +/* horizontal hue bar */ + +/* Vertical hue bar/slider */ + +.DHTMLSuite_colorSlider_hueHorizontal{ + height:40px; + width:360px; + position:relative; + padding-top:10px; + margin-top:5px; + clear:both; +} + + +.DHTMLSuite_colorSlider_hueBarHorizontal_border{ + border-top:2px solid #B2B2B2; + border-left:2px solid #ACA899; + border-bottom:2px solid #FFF; + border-right:2px solid #FFF; + width:360px; + height:20px; + position:relative; + z-index:10; +} + + +.DHTMLSuite_colorSlider_hueBarHorizontal{ + background-image:url('../images/colorPalettes/hueBar-horizontal.png'); + width:360px; + height:20px; + background-color:red; +} +.DHTMLSuite_colorSlider_sliderHandleHorizontal{ + height:41px; + width:9px; + background-image:url('../images/colorPalettes/slider-handle-down.gif'); + background-repeat:no-repeat; + position:absolute; + z-index:15; + top:1px; + left:-4px; + cursor:default; +} +.DHTMLSuite_colorSlider_sliderHandleHorizontal div{ + background-image:url('../images/colorPalettes/slider-handle-up.gif'); + background-repeat:no-repeat; + background-position:top right; + height:9px; + width:9px; + position:absolute; + bottom:0px; +} + + + +.DHTMLSuite_colorSlider_palette{ + width:256px; + height:256px; + float:left; +} + +.DHTMLSuite_colorSlider_palette_circle{ + background-image:url('../images/colorPalettes/circle-selected-black.gif'); + width:13px; + height:13px; + position:absolute; + z-index:100000; + background-position: center center; + background-repeat:no-repeat; + padding:0px; + +} +.DHTMLSuite_colorSlider_palette_circleBlack{ + background-image:url('../images/colorPalettes/circle-selected-black.gif'); +} + +.DHTMLSuite_colorSliderFormDiv{ /* Div element for the form at the right side of the hue bar */ + float:left; + width:100px; + height:256px; +} + +.DHTMLSuite_colorSlider_colorPreview{ + width:80px; + height:50px; + border-left:1px solid #B2B2B2; + border-top:1px solid #B2B2B2; + border-bottom:1px solid #FFF; + border-right:1px solid #FFF; +} + +.DHTMLSuite_colorSliderFormTable{ + font-size:12px; +} + +.DHTMLSuite_colorSliderFormTable input{ + width:30px; + font-family:arial; + font-size:11px; +} +input.DHTMLSuite_colorSlider_rgbCode{ + width:50px; +} + +img{ + behaviour:url('/pngbehavior.htc'); } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/context-menu.css b/ext/dhtml-suite-for-applications/themes/tmw/css/context-menu.css index 6e45045..cb1bc5d 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/context-menu.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/context-menu.css @@ -1,58 +1,58 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, August 2006 - - CSS for the context menu class. - - Terms of use: - Look at the terms of use at http://www.dhtmlgoodies.com/index.html?page=termsOfUse - - Thank you! - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -.DHTMLSuite_contextMenu{ /* The bar that is parent of the menu strip */ - position:absolute; - background-color:#FFF; - border:1px solid #000; - padding:1px; - z-index:100000; -} - -.DHTMLSuite_contextMenu li{ - list-style-type:none; - padding:1px; /* Equal to border + padding of .DHTMLSuite_item_mouseover */ - border:0px; - cursor: pointer; - background-repeat:no-repeat; - background-position:left center; -} -.DHTMLSuite_contextMenu .DHTMLSuite_item_mouseover{ - border:1px solid #000; - background-color:#E2E2E2; - padding:0px; /* Padding + border of this element should be equal to padding of li element (see above ) */ -} -.DHTMLSuite_contextMenu ul{ - margin:0px; - padding:0px; -} - -.DHTMLSuite_contextMenu a{ - text-decoration:none; - color:#000; - padding-left:25px; -} - -.DHTMLSuite_contextMenu div.DHTMLSuite_contextMenu_separator{ /* Css for the separator line */ - height:1px; - line-height:1px; - padding:0px; - background-color: #666; - overflow:hidden; - margin-top:1px; - margin-bottom:1px; -} +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, August 2006 + + CSS for the context menu class. + + Terms of use: + Look at the terms of use at http://www.dhtmlgoodies.com/index.html?page=termsOfUse + + Thank you! + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +.DHTMLSuite_contextMenu{ /* The bar that is parent of the menu strip */ + position:absolute; + background-color:#FFF; + border:1px solid #000; + padding:1px; + z-index:100000; +} + +.DHTMLSuite_contextMenu li{ + list-style-type:none; + padding:1px; /* Equal to border + padding of .DHTMLSuite_item_mouseover */ + border:0px; + cursor: pointer; + background-repeat:no-repeat; + background-position:left center; +} +.DHTMLSuite_contextMenu .DHTMLSuite_item_mouseover{ + border:1px solid #000; + background-color:#E2E2E2; + padding:0px; /* Padding + border of this element should be equal to padding of li element (see above ) */ +} +.DHTMLSuite_contextMenu ul{ + margin:0px; + padding:0px; +} + +.DHTMLSuite_contextMenu a{ + text-decoration:none; + color:#000; + padding-left:25px; +} + +.DHTMLSuite_contextMenu div.DHTMLSuite_contextMenu_separator{ /* Css for the separator line */ + height:1px; + line-height:1px; + padding:0px; + background-color: #666; + overflow:hidden; + margin-top:1px; + margin-bottom:1px; +} diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/drag-drop-folder-tree.css b/ext/dhtml-suite-for-applications/themes/tmw/css/drag-drop-folder-tree.css index 7360db1..909f5e4 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/drag-drop-folder-tree.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/drag-drop-folder-tree.css @@ -1,55 +1,55 @@ -/************************************************************************************************************ -* Drag and drop folder tree (CSS) -* -* Created: August, 23rd, 2006 -* Purpose of class: Transforms an UL,LI list into a folder tree with drag and drop capabilities. -* -* -* Update log: -* -************************************************************************************************************/ - -.DHTMLSuite_tree p{ - font-family:arial; - -} -.DHTMLSuite_tree a{ - color:#000; - font-family:arial; - font-size:0.8em; -} - -.DHTMLSuite_tree,#floatingContainer{ - margin:0px; - padding:0px; - z-index:220000; /* You shouldn't change this value */ -} -.DHTMLSuite_tree ul{ /* Sub menu groups */ - margin-left:20px; /* Left spacing */ - padding-left:0px; - display:none; /* Initially hide sub nodes */ -} - -#floatingContainer ul{ - margin-left:20px; /* Left spacing */ - padding-left:0px; -} -.DHTMLSuite_tree li,#floatingContainer li{ /* Nodes */ - list-style-type:none; - vertical-align:middle; - -} -.DHTMLSuite_tree li a,#floatingContainer li a{ /* Node links */ - color:#000; - text-decoration:none; - font-family:arial; - font-size:0.8em; - padding-left:3px; - line-height:13px; - -} -/* CSS for the imageSelection class. in case nodes in this tree are possible destination nodes for images etc. */ -.DHTMLSuite_tree li a.imageSelection{ - background-color:#316AC5; - color:#FFF; +/************************************************************************************************************ +* Drag and drop folder tree (CSS) +* +* Created: August, 23rd, 2006 +* Purpose of class: Transforms an UL,LI list into a folder tree with drag and drop capabilities. +* +* +* Update log: +* +************************************************************************************************************/ + +.DHTMLSuite_tree p{ + font-family:arial; + +} +.DHTMLSuite_tree a{ + color:#000; + font-family:arial; + font-size:0.8em; +} + +.DHTMLSuite_tree,#floatingContainer{ + margin:0px; + padding:0px; + z-index:220000; /* You shouldn't change this value */ +} +.DHTMLSuite_tree ul{ /* Sub menu groups */ + margin-left:20px; /* Left spacing */ + padding-left:0px; + display:none; /* Initially hide sub nodes */ +} + +#floatingContainer ul{ + margin-left:20px; /* Left spacing */ + padding-left:0px; +} +.DHTMLSuite_tree li,#floatingContainer li{ /* Nodes */ + list-style-type:none; + vertical-align:middle; + +} +.DHTMLSuite_tree li a,#floatingContainer li a{ /* Node links */ + color:#000; + text-decoration:none; + font-family:arial; + font-size:0.8em; + padding-left:3px; + line-height:13px; + +} +/* CSS for the imageSelection class. in case nodes in this tree are possible destination nodes for images etc. */ +.DHTMLSuite_tree li a.imageSelection{ + background-color:#316AC5; + color:#FFF; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/dynamic-tooltip.css b/ext/dhtml-suite-for-applications/themes/tmw/css/dynamic-tooltip.css index a68cd82..f53e920 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/dynamic-tooltip.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/dynamic-tooltip.css @@ -1,37 +1,37 @@ -/* CSS needed for the script */ - -#DHTMLSuite_ajax_tooltipObj{ - z-index:1000000; - text-align:left; -} -#DHTMLSuite_ajax_tooltipObj div{ - position:relative; -} - -/* If you don't want the arrow - Just set the width of this div to 1 or something like that and drop the background selectors from the CSS below */ - -#DHTMLSuite_ajax_tooltipObj .DHTMLSuite_ajax_tooltip_arrow{ /* Left div for the small arrow */ - - width:20px; - position:absolute; - left:0px; - top:0px; - background-repeat:no-repeat; - background-position:center left; - z-index:1000005; - height:60px; -} - -#DHTMLSuite_ajax_tooltipObj .DHTMLSuite_ajax_tooltip_content{ - border:2px solid #317082; /* Border width */ - left:18px; /* Same as border thickness */ - top:0px; - position:absolute; - width:150px; /* Width of tooltip content */ - height:200px; /* Height of tooltip content */ - background-color:#FFF; /* Background color */ - padding:5px; /* Space between border and content */ - font-size:0.8em; /* Font size of content */ - overflow:auto; /* Hide overflow content */ - z-index:1000001; +/* CSS needed for the script */ + +#DHTMLSuite_ajax_tooltipObj{ + z-index:1000000; + text-align:left; +} +#DHTMLSuite_ajax_tooltipObj div{ + position:relative; +} + +/* If you don't want the arrow - Just set the width of this div to 1 or something like that and drop the background selectors from the CSS below */ + +#DHTMLSuite_ajax_tooltipObj .DHTMLSuite_ajax_tooltip_arrow{ /* Left div for the small arrow */ + + width:20px; + position:absolute; + left:0px; + top:0px; + background-repeat:no-repeat; + background-position:center left; + z-index:1000005; + height:60px; +} + +#DHTMLSuite_ajax_tooltipObj .DHTMLSuite_ajax_tooltip_content{ + border:2px solid #317082; /* Border width */ + left:18px; /* Same as border thickness */ + top:0px; + position:absolute; + width:150px; /* Width of tooltip content */ + height:200px; /* Height of tooltip content */ + background-color:#FFF; /* Background color */ + padding:5px; /* Space between border and content */ + font-size:0.8em; /* Font size of content */ + overflow:auto; /* Hide overflow content */ + z-index:1000001; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/filmstrip-gallery.css b/ext/dhtml-suite-for-applications/themes/tmw/css/filmstrip-gallery.css index 5906fe8..3d38772 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/filmstrip-gallery.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/filmstrip-gallery.css @@ -1,44 +1,44 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, Janury 2007 - - CSS for the DHTMLSuite.filmstripGallery class. - - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -/* Set the and element to full size and overflow to hidden -This is important for the script -*/ -.DHTMLSuite_filmstripGalleryContainer{ /* Pane content div */ - - - -} - -.DHTMLSuite_filmstripGalleryContainer .DHTMLSuite_filmstripGalleryImageBox{ - float:left; - width:120px; - height:170px; - position:relative; - margin:3px; - border:2px solid #CCC; - background-position: center 20px; - background-repeat:no-repeat; - cursor:pointer; -} - -.DHTMLSuite_filmstripGalleryContainer .DHTMLSuite_filmstripGalleryImageBox .DHTMLSuite_filmstripGalleryImageTitle{ - position:absolute; - bottom:0px; - left:0px; - text-align:center; - width:100%; - background-color:#EEE; - border-top:2px solid #CCC; - +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, Janury 2007 + + CSS for the DHTMLSuite.filmstripGallery class. + + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +/* Set the and element to full size and overflow to hidden +This is important for the script +*/ +.DHTMLSuite_filmstripGalleryContainer{ /* Pane content div */ + + + +} + +.DHTMLSuite_filmstripGalleryContainer .DHTMLSuite_filmstripGalleryImageBox{ + float:left; + width:120px; + height:170px; + position:relative; + margin:3px; + border:2px solid #CCC; + background-position: center 20px; + background-repeat:no-repeat; + cursor:pointer; +} + +.DHTMLSuite_filmstripGalleryContainer .DHTMLSuite_filmstripGalleryImageBox .DHTMLSuite_filmstripGalleryImageTitle{ + position:absolute; + bottom:0px; + left:0px; + text-align:center; + width:100%; + background-color:#EEE; + border-top:2px solid #CCC; + } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/floating-gallery.css b/ext/dhtml-suite-for-applications/themes/tmw/css/floating-gallery.css index 6b96063..1672087 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/floating-gallery.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/floating-gallery.css @@ -1,51 +1,51 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, Janury 2007 - - CSS for the DHTMLSuite.floatingGallery class. - - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -/* Set the and element to full size and overflow to hidden -This is important for the script -*/ -.DHTMLSuite_floatingGalleryContainer{ /* Pane content div */ - - - -} - -.DHTMLSuite_floatingGalleryContainer .DHTMLSuite_floatingGalleryImageBox{ - float:left; - width:120px; - height:170px; - position:relative; - margin:3px; - border:2px solid #888; - background-position: center 20px; - background-repeat:no-repeat; - cursor:pointer; -} - -/* Special effects when an imageSelection object is used. This css is used to inform the user that the current element is selected */ - -.DHTMLSuite_floatingGalleryContainer .imageSelection{ - border:2px solid #222; -} - -.DHTMLSuite_floatingGalleryContainer .DHTMLSuite_floatingGalleryImageBox .DHTMLSuite_floatingGalleryImageTitle{ - position:absolute; - bottom:0px; - left:0px; - text-align:center; - width:100%; - background-color:#888; - border-top:2px solid #CCC; - color:#FFF; - +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, Janury 2007 + + CSS for the DHTMLSuite.floatingGallery class. + + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +/* Set the and element to full size and overflow to hidden +This is important for the script +*/ +.DHTMLSuite_floatingGalleryContainer{ /* Pane content div */ + + + +} + +.DHTMLSuite_floatingGalleryContainer .DHTMLSuite_floatingGalleryImageBox{ + float:left; + width:120px; + height:170px; + position:relative; + margin:3px; + border:2px solid #888; + background-position: center 20px; + background-repeat:no-repeat; + cursor:pointer; +} + +/* Special effects when an imageSelection object is used. This css is used to inform the user that the current element is selected */ + +.DHTMLSuite_floatingGalleryContainer .imageSelection{ + border:2px solid #222; +} + +.DHTMLSuite_floatingGalleryContainer .DHTMLSuite_floatingGalleryImageBox .DHTMLSuite_floatingGalleryImageTitle{ + position:absolute; + bottom:0px; + left:0px; + text-align:center; + width:100%; + background-color:#888; + border-top:2px solid #CCC; + color:#FFF; + } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/image-enlarger.css b/ext/dhtml-suite-for-applications/themes/tmw/css/image-enlarger.css index 8c89be0..f201232 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/image-enlarger.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/image-enlarger.css @@ -1,89 +1,89 @@ -/************************************************************************************************************ -* DHTML image enlarger (CSS for the DHTMLSuite.imageEnlarger class) -* -* -* -* Update log: -* -************************************************************************************************************/ - -.DHTMLSuite_imageEnlarger_transparentDivs{ - filter:alpha(opacity=50); /* Transparency */ - opacity:0.5; /* Transparency */ - -moz-opacity:0.5; /* Transparency */ - background-color:#000; - z-index:1; - position:absolute; /* Always needed */ - z-index:100000; - top:0px; - left:0px; -} -.DHTMLSuite_imageEnlarger_iframe{ - z-index:100010; - position:absolute; - background-color:#FFF; - left:0px; - top:0px; -} -.DHTMLSuite_imageEnlarger{ /* Main div - no layout on this */ - position:absolute; - z-index:100017; - left:50%; - top:50%; -} - -.DHTMLSuite_imageEnlarger_imageBox{ /* div element inside main div - This is the place to add layout */ - position:absolute; - z-index:100020; - background-color:#000; - border:8px solid #000; - -} -.DHTMLSuite_imageEnlarger_caption{ /* Image caption */ - background-color:#000; - color:#FFF; - padding:5px; - text-align:center; -} -.DHTMLSuite_imageEnlarger_close,.DHTMLSuite_imageEnlarger_closeOver{ /* Close button */ - position:absolute; - top:0px; - right:0px; - background-repeat:no-repeat; - background-position:top right; - width:15px; - height:15px; - cursor:pointer; -} -.DHTMLSuite_imageEnlarger_closeOver{ /* Close button - mouse over */ - background-image:url('../images/image-enlarger/imageEnlarger_close_over.png'); -} -.DHTMLSuite_imageEnlarger_close{ /* Close button */ - background-image:url('../images/image-enlarger/imageEnlarger_close.png'); -} - -span.DHTMLSuite_imageEnlarger_captionTitle{ /* Image caption - title */ - display:block; - font-weight:bold; - font-style:italic; -} -span.DHTMLSuite_imageEnlarger_captionDescription{ /* Image caption - the caption */ - display:block; -} -a.DHTMLSuite_imageEnlarger_closeLink{ /* Close link below the caption - If you don't want it, just set display:none as a new css rule for this class */ - text-align:center; - display:block; - color:red; - text-decoration:underline; -} - -/* THIS SHADOW DIV HAS NOT BEEN IMPLEMENTED */ -.DHTMLSuite_imageEnlarger_shadow{ - position:absolute; - background-color:#000; - filter:alpha(opacity=70); /* Transparency */ - opacity:0.7; /* Transparency */ - -moz-opacity:0.7; /* Transparency */ - z-index:100019; - -} +/************************************************************************************************************ +* DHTML image enlarger (CSS for the DHTMLSuite.imageEnlarger class) +* +* +* +* Update log: +* +************************************************************************************************************/ + +.DHTMLSuite_imageEnlarger_transparentDivs{ + filter:alpha(opacity=50); /* Transparency */ + opacity:0.5; /* Transparency */ + -moz-opacity:0.5; /* Transparency */ + background-color:#000; + z-index:1; + position:absolute; /* Always needed */ + z-index:100000; + top:0px; + left:0px; +} +.DHTMLSuite_imageEnlarger_iframe{ + z-index:100010; + position:absolute; + background-color:#FFF; + left:0px; + top:0px; +} +.DHTMLSuite_imageEnlarger{ /* Main div - no layout on this */ + position:absolute; + z-index:100017; + left:50%; + top:50%; +} + +.DHTMLSuite_imageEnlarger_imageBox{ /* div element inside main div - This is the place to add layout */ + position:absolute; + z-index:100020; + background-color:#000; + border:8px solid #000; + +} +.DHTMLSuite_imageEnlarger_caption{ /* Image caption */ + background-color:#000; + color:#FFF; + padding:5px; + text-align:center; +} +.DHTMLSuite_imageEnlarger_close,.DHTMLSuite_imageEnlarger_closeOver{ /* Close button */ + position:absolute; + top:0px; + right:0px; + background-repeat:no-repeat; + background-position:top right; + width:15px; + height:15px; + cursor:pointer; +} +.DHTMLSuite_imageEnlarger_closeOver{ /* Close button - mouse over */ + background-image:url('../images/image-enlarger/imageEnlarger_close_over.png'); +} +.DHTMLSuite_imageEnlarger_close{ /* Close button */ + background-image:url('../images/image-enlarger/imageEnlarger_close.png'); +} + +span.DHTMLSuite_imageEnlarger_captionTitle{ /* Image caption - title */ + display:block; + font-weight:bold; + font-style:italic; +} +span.DHTMLSuite_imageEnlarger_captionDescription{ /* Image caption - the caption */ + display:block; +} +a.DHTMLSuite_imageEnlarger_closeLink{ /* Close link below the caption - If you don't want it, just set display:none as a new css rule for this class */ + text-align:center; + display:block; + color:red; + text-decoration:underline; +} + +/* THIS SHADOW DIV HAS NOT BEEN IMPLEMENTED */ +.DHTMLSuite_imageEnlarger_shadow{ + position:absolute; + background-color:#000; + filter:alpha(opacity=70); /* Transparency */ + opacity:0.7; /* Transparency */ + -moz-opacity:0.7; /* Transparency */ + z-index:100019; + +} diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/image-selection.css b/ext/dhtml-suite-for-applications/themes/tmw/css/image-selection.css index 593a2e9..8eebb83 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/image-selection.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/image-selection.css @@ -1,68 +1,68 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, Janury 2007 - - CSS for the DHTMLSuite.imageSelection class. - - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -/* Mane selection div - the dragable rectangle */ -#DHTMLSuite_imageSelectionSel{ - position:absolute; - overflow:hidden; - border:1px solid #222; /* Blue border */ - z-index:5000000; -} -/* Transparent div inside the image selection div */ -#DHTMLSuite_imageSelection_transparentDiv{ /* This is the transparent div placed inside #DHTMLSuite_imageSelection */ - filter:alpha(opacity=50); - opacity:0.5; - -moz-opacity:0.5; - background-color:#666; /* Blue background color */ - position:absolute; - left:-5px; - top:-5px; - width:200%; - height:200%; -} - -/* Div for the drag process - dragging images */ -#DHTMLSuite_imageSelectionDrag{ - position:absolute; - border:1px solid #222; - z-index:5000000; - overflow:hidden; - width:107px; -} - -#DHTMLSuite_imageSelectionDrag #DHTMLSuite_imageSelectionDragContent{ - padding:0px; - z-index:5; - position:relative; -} - -/* Div for the drag process - small boxes for each image. These divs are placed inside #DHTMLSuite_imageSelectionDragContent */ -#DHTMLSuite_imageSelectionDrag .DHTMLSuite_imageSelectionDragBox{ /* Individual box for each image */ - width:35px; - height:35px; - float:left; - background-repeat:no-repeat; - background-position:center center; - -} - -/* Div inside the div with id #DHTMLSuite_imageSelectionDrag - it could be transparent or not, that's your choice */ -#DHTMLSuite_imageSelectionDrag .DHTMLSuite_imageSelectionDrag_transparentDiv{ - background-color:#666; /* Blue background color */ - position:absolute; - left:-5px; - top:-5px; - width:200%; - height:200%; - z-index:4; +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, Janury 2007 + + CSS for the DHTMLSuite.imageSelection class. + + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +/* Mane selection div - the dragable rectangle */ +#DHTMLSuite_imageSelectionSel{ + position:absolute; + overflow:hidden; + border:1px solid #222; /* Blue border */ + z-index:5000000; +} +/* Transparent div inside the image selection div */ +#DHTMLSuite_imageSelection_transparentDiv{ /* This is the transparent div placed inside #DHTMLSuite_imageSelection */ + filter:alpha(opacity=50); + opacity:0.5; + -moz-opacity:0.5; + background-color:#666; /* Blue background color */ + position:absolute; + left:-5px; + top:-5px; + width:200%; + height:200%; +} + +/* Div for the drag process - dragging images */ +#DHTMLSuite_imageSelectionDrag{ + position:absolute; + border:1px solid #222; + z-index:5000000; + overflow:hidden; + width:107px; +} + +#DHTMLSuite_imageSelectionDrag #DHTMLSuite_imageSelectionDragContent{ + padding:0px; + z-index:5; + position:relative; +} + +/* Div for the drag process - small boxes for each image. These divs are placed inside #DHTMLSuite_imageSelectionDragContent */ +#DHTMLSuite_imageSelectionDrag .DHTMLSuite_imageSelectionDragBox{ /* Individual box for each image */ + width:35px; + height:35px; + float:left; + background-repeat:no-repeat; + background-position:center center; + +} + +/* Div inside the div with id #DHTMLSuite_imageSelectionDrag - it could be transparent or not, that's your choice */ +#DHTMLSuite_imageSelectionDrag .DHTMLSuite_imageSelectionDrag_transparentDiv{ + background-color:#666; /* Blue background color */ + position:absolute; + left:-5px; + top:-5px; + width:200%; + height:200%; + z-index:4; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/info-pane.css b/ext/dhtml-suite-for-applications/themes/tmw/css/info-pane.css index 93d2ba7..509d34f 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/info-pane.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/info-pane.css @@ -1,80 +1,80 @@ -.DHTMLSuite_panel{ - margin-left:10px; - margin-right:10px; - margin-top:10px; -} -.DHTMLSuite_panelContent{ - font-size:0.7em; - background-position:top right; - border-left:1px solid #FFF; - border-bottom:1px solid #FFF; - padding-left:2px; - padding-right:2px; - overflow:hidden; - position:relative; - clear:both; -} -.DHTMLSuite_panelContent div{ - position:relative; - text-align:left; - top:0px; -} -.DHTMLSuite_panel .DHTMLSuite_infoPaneTopBar{ - background-repeat:repeat-x; - height:23px; - padding-right:5px; - cursor:pointer; - overflow:hidden; - -} - - -.DHTMLSuite_infoPane_topBar_button{ - position:absolute; - background-position:center center; - background-repeat:no-repeat; - right:3px; - top:4px; - background-image:url(../images/info-pane/xp-info-pane-arrow_up.gif); - background-repeat:no-repeat; - height:13px; - width:13px; - padding:1px; - border:0px; -} - -.DHTMLSuite_infoPaneButton_over{ - background-color:#FFA160; - border:1px solid #BE510E; - padding:0px; -} - -.DHTMLSuite_infoPane_topBar_buttonDown{ - background-image:url(../images/info-pane/xp-info-pane-arrow_down.gif); -} - - -.DHTMLSuite_panel .DHTMLSuite_infoPaneTopBar span{ - line-height:23px; - vertical-align:middle; - font-family:arial; - font-size:0.7em; - color:#FFEDC8; - font-weight:bold; - float:left; - padding-left:5px; -} -.DHTMLSuite_panel .DHTMLSuite_infoPaneTopBar img{ - float:right; - cursor:pointer; -} - -.DHTMLSuite_xpPane{ - background-color:#494949; - float:left; - height:1200px; - width:200px; -} -.DHTMLSuite_xpPane span.DHTMLSuite_infoPanelOver{ - color:#FFF; +.DHTMLSuite_panel{ + margin-left:10px; + margin-right:10px; + margin-top:10px; +} +.DHTMLSuite_panelContent{ + font-size:0.7em; + background-position:top right; + border-left:1px solid #FFF; + border-bottom:1px solid #FFF; + padding-left:2px; + padding-right:2px; + overflow:hidden; + position:relative; + clear:both; +} +.DHTMLSuite_panelContent div{ + position:relative; + text-align:left; + top:0px; +} +.DHTMLSuite_panel .DHTMLSuite_infoPaneTopBar{ + background-repeat:repeat-x; + height:23px; + padding-right:5px; + cursor:pointer; + overflow:hidden; + +} + + +.DHTMLSuite_infoPane_topBar_button{ + position:absolute; + background-position:center center; + background-repeat:no-repeat; + right:3px; + top:4px; + background-image:url(../images/info-pane/xp-info-pane-arrow_up.gif); + background-repeat:no-repeat; + height:13px; + width:13px; + padding:1px; + border:0px; +} + +.DHTMLSuite_infoPaneButton_over{ + background-color:#FFA160; + border:1px solid #BE510E; + padding:0px; +} + +.DHTMLSuite_infoPane_topBar_buttonDown{ + background-image:url(../images/info-pane/xp-info-pane-arrow_down.gif); +} + + +.DHTMLSuite_panel .DHTMLSuite_infoPaneTopBar span{ + line-height:23px; + vertical-align:middle; + font-family:arial; + font-size:0.7em; + color:#FFEDC8; + font-weight:bold; + float:left; + padding-left:5px; +} +.DHTMLSuite_panel .DHTMLSuite_infoPaneTopBar img{ + float:right; + cursor:pointer; +} + +.DHTMLSuite_xpPane{ + background-color:#494949; + float:left; + height:1200px; + width:200px; +} +.DHTMLSuite_xpPane span.DHTMLSuite_infoPanelOver{ + color:#FFF; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/menu-bar.css b/ext/dhtml-suite-for-applications/themes/tmw/css/menu-bar.css index 9d3e1c1..b614ada 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/menu-bar.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/menu-bar.css @@ -1,58 +1,58 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, August 2006 - - CSS for the DHTMLsuite_tableWidget class. - - Terms of use: - Look at the terms of use at http://www.dhtmlgoodies.com/index.html?page=termsOfUse - - Thank you! - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -.DHTMLSuite_menuBar_top{ /* The bar that is parent of the menu strip */ - height:26px; - background-repeat:repeat-x; - font-family: Arial; - font-size:12px; - z-index:100000; - padding-left:10px; - background-image:url('../images/menu-bar/menu_strip_bg.jpg'); -} - -.DHTMLSuite_menuBar_sub{ - position:absolute; - background-color:#FFF; - border:1px solid #000; - background-image:url('../images/menu-bar/menu-bar-gradient.jpg'); /* Background image for sub menu items */ - background-repeat:repeat-y; - background-position: left center; - -} - -#menuBarContainer{ - background-image:url('../images/menu-bar/left-bg-menustrip.png'); - background-repeat:no-repeat; - padding-left:1px; - position:relative; - padding-right:0px; - -} -#menuBarContainer #innerDiv{ - background-repeat:repeat-x; -} -#menuBarContainer #rightDiv{ - background-image:url('../images/menu-bar/right-bg-menustrip.png'); - background-repeat:no-repeat; - background-position:top right; - height:25px; - width:20px; - position:absolute; - right:0px; - top:0px; +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, August 2006 + + CSS for the DHTMLsuite_tableWidget class. + + Terms of use: + Look at the terms of use at http://www.dhtmlgoodies.com/index.html?page=termsOfUse + + Thank you! + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +.DHTMLSuite_menuBar_top{ /* The bar that is parent of the menu strip */ + height:26px; + background-repeat:repeat-x; + font-family: Arial; + font-size:12px; + z-index:100000; + padding-left:10px; + background-image:url('../images/menu-bar/menu_strip_bg.jpg'); +} + +.DHTMLSuite_menuBar_sub{ + position:absolute; + background-color:#FFF; + border:1px solid #000; + background-image:url('../images/menu-bar/menu-bar-gradient.jpg'); /* Background image for sub menu items */ + background-repeat:repeat-y; + background-position: left center; + +} + +#menuBarContainer{ + background-image:url('../images/menu-bar/left-bg-menustrip.png'); + background-repeat:no-repeat; + padding-left:1px; + position:relative; + padding-right:0px; + +} +#menuBarContainer #innerDiv{ + background-repeat:repeat-x; +} +#menuBarContainer #rightDiv{ + background-image:url('../images/menu-bar/right-bg-menustrip.png'); + background-repeat:no-repeat; + background-position:top right; + height:25px; + width:20px; + position:absolute; + right:0px; + top:0px; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/menu-item.css b/ext/dhtml-suite-for-applications/themes/tmw/css/menu-item.css index 763eb60..0717cef 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/menu-item.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/menu-item.css @@ -1,193 +1,193 @@ -/* CSS FOR MENU ITEM OF TYPE "top" */ - -.DHTMLSuite_menuItem_top_regular,.DHTMLSuite_menuItem_top_over,.DHTMLSuite_menuItem_top_click,.DHTMLSuite_menuItem_top_disabled,.DHTMLSuite_menuItem_top_active{ - height:17px; - margin-top:3px; -} -.DHTMLSuite_menuItem_top_regular div,.DHTMLSuite_menuItem_top_over div,.DHTMLSuite_menuItem_top_click div,.DHTMLSuite_menuItem_top_disabled div,.DHTMLSuite_menuItem_top_active div{ - padding-top:2px; - padding-bottom:2px; -} -.DHTMLSuite_menuItem_top_regular{ /* Top level menu item - Regular state */ - padding-left:4px; - padding-right:4px; - margin-right:2px; - padding-top:1px; - padding-bottom:1px; - cursor:pointer; - line-height:14px - margin-top:2px; - color:#DDD; -} - -.DHTMLSuite_menuItem_top_over{ /* Top level menu item - Mouse over state */ - padding-left:3px; - padding-right:3px; - margin-right:2px; - border:1px solid #000; - background-color:#AAA; - cursor:pointer; - line-height:14px - margin-top:2px; -} - -.DHTMLSuite_menuItem_top_active{ /* Top level menu item - Active state - this is typical the state for menu item 1 when a sub group is expanded and the mouse is located over one of the sub menu items */ - padding-left:3px; - padding-right:3px; - margin-right:2px; - border:1px solid #000; - border-bottom:1px solid #000; - background-color:#999; - cursor:pointer; - line-height:14px - margin-top:2px; - -} - -.DHTMLSuite_menuItem_top_click{ /* Top level menu item - Mouse click state */ - padding-left:3px; - padding-right:3px; - margin-right:2px; - border:1px solid #000; - background-color:#999; - cursor:pointer; - line-height:14px - margin-top:2px; - z-index:20000; -} - -.DHTMLSuite_menuItem_top_disabled{ /* Disabled menu item */ - padding-left:4px; - padding-right:4px; - margin-right:2px; - padding-top:1px; - padding-bottom:1px; - cursor:default; - line-height:14px - margin-top:2px; -} - -.DHTMLSuite_menuItem_top_disabled img,.DHTMLSuite_menuItem_top_disabled div{ /* Sub divs of disabled top level items. A menu item is a div with some subdivs(one for the icon, one for text etc.). this is the css for these sub divs */ - filter:alpha(opacity=40); /* Transparency */ - opacity:0.4; /* Transparency */ - -moz-opacity:0.4; /* Transparency */ - -khtml-opacity:.4; /* Transparency */ -} - -.DHTMLSuite_menuItem_top_disabled div,.DHTMLSuite_menuItem_top_active div, .DHTMLSuite_menuItem_top_click div, .DHTMLSuite_menuItem_top_regular div,.DHTMLSuite_menuItem_top_over div{ /* divs for the text,icon and arrow of a menu item */ - float:left; - padding-left:1px; - padding-right:1px; -} - -/* CSS FOR THE SMALL ARROW DIV - WHEN YOU CLICK ON THIS DIV, SUB ELEMENTS WILL SHOW */ -.DHTMLSuite_menuItem_top_arrowShowSub{ /* This is the arrow for top level elements */ - width:12px; /* Width of item */ - background-repeat:no-repeat; /* No background repeat for the arrow */ - background-position:center center; /* Position of the arrow. at the center of this div */ - background-image: url('../images/menu-item/menu_strip_down_arrow.gif'); /* Relative path to the arrow */ - margin:0px; - margin-right:-1px; /* -1 pixel is added to get the arrow a little bit more to the right. this is because of the right padding of top level items */ - padding:0px; - height:14px; - margin-left:2px; - float:right; -} -head:first-child+body .DHTMLSuite_menuItem_top_arrowShowSub { /* Transparent png for other browsers than IE6 */ - background-image: url('../images/menu-item/menu_strip_down_arrow.png'); /* Relative path to the arrow */ -} - - -.DHTMLSuite_menuItem_top_over .DHTMLSuite_menuItem_top_arrowShowSub, -.DHTMLSuite_menuItem_top_click .DHTMLSuite_menuItem_top_arrowShowSub -{ /* Sub menu arrows */ - margin-left:1px; - border-left:1px solid #000; -} - -/* CSS FOR SEPARATOR */ - -.DHTMLSuite_menuItem_separator_top{ /* Separator of type "top" */ - height:20px; - margin-top:3px; - margin-bottom:3px; - width:4px; - padding-left:3px; - padding-right:3px; - background-repeat:repeat-y; - background-image:url('../images/menu-item/menu_strip_separator.gif'); - -} - - -/* CSS FOR MENU ITEM OF TYPE "sub" */ - -.DHTMLSuite_menuItem_sub_regular, .DHTMLSuite_menuItem_sub_over,.DHTMLSuite_menuItem_sub_click,.DHTMLSuite_menuItem_sub_disabled,.DHTMLSuite_menuItem_sub_active{ /* Commom css for regular, mouse over and mouse click items */ - clear:both; - line-height:18px; /* Height of menu item */ - height:18px; /* Height of menu item */ - padding-left:25px; /* Space inside the menu item - the 25 pixels are used in order to avoid text overlapping menu item icon */ - padding-right:4px; /* Space inside the menu item */ - padding-top:2px; /* Space inside the menu item */ - padding-bottom:2px; /* Space inside the menu item */ - cursor:pointer; /* Mouse cursor set to a "hand" */ - margin:1px; /* A little space around the item */ - background-repeat:no-repeat; /* No background repeat */ -} -.DHTMLSuite_menuItem_sub_disabled{ /* Disabled sub menu item */ - cursor:default; /* Arrow as cursor instead of hand */ -} -.DHTMLSuite_menuItem_sub_disabled div,.DHTMLSuite_menuItem_sub_disabled{ /* Disabled sub menu item - Here, we apply the rules on the divs inside the element, i.e. the div for the icon, text and arrow */ - filter:alpha(opacity=40); /* Transparency */ - opacity:0.4; /* Transparency */ - -moz-opacity:0.4; /* Transparency */ - -khtml-opacity:.4; /* Transparency */ -} -.DHTMLSuite_menuItem_sub_regular,.DHTMLSuite_menuItem_sub_disabled{ /* Regular menu item */ - margin-left:2px; /* size of margin above + 1 pixel */ - padding-top:3px; /* Size of padding-top above + 1 pixel */ - padding-bottom:3px; /* Size of padding-bottom above + 1 pixel */ -} - -.DHTMLSuite_menuItem_sub_over,.DHTMLSuite_menuItem_sub_click,.DHTMLSuite_menuItem_sub_active{ - border:1px solid #222; /* Border around mouse over items, click items and active items */ -} - -.DHTMLSuite_menuItem_sub_over,.DHTMLSuite_menuItem_sub_active{ /* Mouse over effect */ - background-color:#E2E2E2; /* Background color of mouse over items and active items(Active item = parent elements of the menu item the mouse is currently over */ -} - -.DHTMLSuite_menuItem_sub_click{ /* Mouse click effect */ - background-color:#CCCCCC; /* Background color when the mouse button is pressed down on a menu item */ -} - -.DHTMLSuite_menuItem_sub_click div, .DHTMLSuite_menuItem_sub_regular div,.DHTMLSuite_menuItem_sub_over div,.DHTMLSuite_menuItem_sub_active div,.DHTMLSuite_menuItem_sub_disabled div{ /* divs for the text,icon and arrow of a menu item */ - float:left; /* To get the icons and text of sub elements side by side */ - padding-left:1px; - padding-right:1px; - -} -.DHTMLSuite_menuItem_sub_arrowShowSub{ /* Arrow div for sub elements (Right pointing arrow ) */ - position:absolute; /* Never change this one */ - background-image:url('../images/menu-item/menu-bar-right-arrow.gif'); /* Path relative to the css file */ - width:18px; - height:18px; - text-align:right; - right:0px; - background-repeat:no-repeat; /* No background repeat */ - background-position: center right; /* Position of arrow */ -} -head:first-child+body .DHTMLSuite_menuItem_sub_arrowShowSub { /* Transparent png for other browsers than IE6 */ - background-image: url('../images/menu-item/menu-bar-right-arrow.png'); /* Relative path to the arrow */ -} - -.DHTMLSuite_menuItem_separator_sub{ /* Separator of type "sub" */ - height:1px; /* Height of separator */ - margin-top:1px; /* Space above the separator */ - margin-bottom:1px; /* Space below the separator */ - margin-left:24px; /* left margin because we don't want the separator to cover the gradient */ - padding-right:3px; /* space at the right of the separator */ - background-color:#222; /* background color for the separator - blue */ -} - - +/* CSS FOR MENU ITEM OF TYPE "top" */ + +.DHTMLSuite_menuItem_top_regular,.DHTMLSuite_menuItem_top_over,.DHTMLSuite_menuItem_top_click,.DHTMLSuite_menuItem_top_disabled,.DHTMLSuite_menuItem_top_active{ + height:17px; + margin-top:3px; +} +.DHTMLSuite_menuItem_top_regular div,.DHTMLSuite_menuItem_top_over div,.DHTMLSuite_menuItem_top_click div,.DHTMLSuite_menuItem_top_disabled div,.DHTMLSuite_menuItem_top_active div{ + padding-top:2px; + padding-bottom:2px; +} +.DHTMLSuite_menuItem_top_regular{ /* Top level menu item - Regular state */ + padding-left:4px; + padding-right:4px; + margin-right:2px; + padding-top:1px; + padding-bottom:1px; + cursor:pointer; + line-height:14px + margin-top:2px; + color:#DDD; +} + +.DHTMLSuite_menuItem_top_over{ /* Top level menu item - Mouse over state */ + padding-left:3px; + padding-right:3px; + margin-right:2px; + border:1px solid #000; + background-color:#AAA; + cursor:pointer; + line-height:14px + margin-top:2px; +} + +.DHTMLSuite_menuItem_top_active{ /* Top level menu item - Active state - this is typical the state for menu item 1 when a sub group is expanded and the mouse is located over one of the sub menu items */ + padding-left:3px; + padding-right:3px; + margin-right:2px; + border:1px solid #000; + border-bottom:1px solid #000; + background-color:#999; + cursor:pointer; + line-height:14px + margin-top:2px; + +} + +.DHTMLSuite_menuItem_top_click{ /* Top level menu item - Mouse click state */ + padding-left:3px; + padding-right:3px; + margin-right:2px; + border:1px solid #000; + background-color:#999; + cursor:pointer; + line-height:14px + margin-top:2px; + z-index:20000; +} + +.DHTMLSuite_menuItem_top_disabled{ /* Disabled menu item */ + padding-left:4px; + padding-right:4px; + margin-right:2px; + padding-top:1px; + padding-bottom:1px; + cursor:default; + line-height:14px + margin-top:2px; +} + +.DHTMLSuite_menuItem_top_disabled img,.DHTMLSuite_menuItem_top_disabled div{ /* Sub divs of disabled top level items. A menu item is a div with some subdivs(one for the icon, one for text etc.). this is the css for these sub divs */ + filter:alpha(opacity=40); /* Transparency */ + opacity:0.4; /* Transparency */ + -moz-opacity:0.4; /* Transparency */ + -khtml-opacity:.4; /* Transparency */ +} + +.DHTMLSuite_menuItem_top_disabled div,.DHTMLSuite_menuItem_top_active div, .DHTMLSuite_menuItem_top_click div, .DHTMLSuite_menuItem_top_regular div,.DHTMLSuite_menuItem_top_over div{ /* divs for the text,icon and arrow of a menu item */ + float:left; + padding-left:1px; + padding-right:1px; +} + +/* CSS FOR THE SMALL ARROW DIV - WHEN YOU CLICK ON THIS DIV, SUB ELEMENTS WILL SHOW */ +.DHTMLSuite_menuItem_top_arrowShowSub{ /* This is the arrow for top level elements */ + width:12px; /* Width of item */ + background-repeat:no-repeat; /* No background repeat for the arrow */ + background-position:center center; /* Position of the arrow. at the center of this div */ + background-image: url('../images/menu-item/menu_strip_down_arrow.gif'); /* Relative path to the arrow */ + margin:0px; + margin-right:-1px; /* -1 pixel is added to get the arrow a little bit more to the right. this is because of the right padding of top level items */ + padding:0px; + height:14px; + margin-left:2px; + float:right; +} +head:first-child+body .DHTMLSuite_menuItem_top_arrowShowSub { /* Transparent png for other browsers than IE6 */ + background-image: url('../images/menu-item/menu_strip_down_arrow.png'); /* Relative path to the arrow */ +} + + +.DHTMLSuite_menuItem_top_over .DHTMLSuite_menuItem_top_arrowShowSub, +.DHTMLSuite_menuItem_top_click .DHTMLSuite_menuItem_top_arrowShowSub +{ /* Sub menu arrows */ + margin-left:1px; + border-left:1px solid #000; +} + +/* CSS FOR SEPARATOR */ + +.DHTMLSuite_menuItem_separator_top{ /* Separator of type "top" */ + height:20px; + margin-top:3px; + margin-bottom:3px; + width:4px; + padding-left:3px; + padding-right:3px; + background-repeat:repeat-y; + background-image:url('../images/menu-item/menu_strip_separator.gif'); + +} + + +/* CSS FOR MENU ITEM OF TYPE "sub" */ + +.DHTMLSuite_menuItem_sub_regular, .DHTMLSuite_menuItem_sub_over,.DHTMLSuite_menuItem_sub_click,.DHTMLSuite_menuItem_sub_disabled,.DHTMLSuite_menuItem_sub_active{ /* Commom css for regular, mouse over and mouse click items */ + clear:both; + line-height:18px; /* Height of menu item */ + height:18px; /* Height of menu item */ + padding-left:25px; /* Space inside the menu item - the 25 pixels are used in order to avoid text overlapping menu item icon */ + padding-right:4px; /* Space inside the menu item */ + padding-top:2px; /* Space inside the menu item */ + padding-bottom:2px; /* Space inside the menu item */ + cursor:pointer; /* Mouse cursor set to a "hand" */ + margin:1px; /* A little space around the item */ + background-repeat:no-repeat; /* No background repeat */ +} +.DHTMLSuite_menuItem_sub_disabled{ /* Disabled sub menu item */ + cursor:default; /* Arrow as cursor instead of hand */ +} +.DHTMLSuite_menuItem_sub_disabled div,.DHTMLSuite_menuItem_sub_disabled{ /* Disabled sub menu item - Here, we apply the rules on the divs inside the element, i.e. the div for the icon, text and arrow */ + filter:alpha(opacity=40); /* Transparency */ + opacity:0.4; /* Transparency */ + -moz-opacity:0.4; /* Transparency */ + -khtml-opacity:.4; /* Transparency */ +} +.DHTMLSuite_menuItem_sub_regular,.DHTMLSuite_menuItem_sub_disabled{ /* Regular menu item */ + margin-left:2px; /* size of margin above + 1 pixel */ + padding-top:3px; /* Size of padding-top above + 1 pixel */ + padding-bottom:3px; /* Size of padding-bottom above + 1 pixel */ +} + +.DHTMLSuite_menuItem_sub_over,.DHTMLSuite_menuItem_sub_click,.DHTMLSuite_menuItem_sub_active{ + border:1px solid #222; /* Border around mouse over items, click items and active items */ +} + +.DHTMLSuite_menuItem_sub_over,.DHTMLSuite_menuItem_sub_active{ /* Mouse over effect */ + background-color:#E2E2E2; /* Background color of mouse over items and active items(Active item = parent elements of the menu item the mouse is currently over */ +} + +.DHTMLSuite_menuItem_sub_click{ /* Mouse click effect */ + background-color:#CCCCCC; /* Background color when the mouse button is pressed down on a menu item */ +} + +.DHTMLSuite_menuItem_sub_click div, .DHTMLSuite_menuItem_sub_regular div,.DHTMLSuite_menuItem_sub_over div,.DHTMLSuite_menuItem_sub_active div,.DHTMLSuite_menuItem_sub_disabled div{ /* divs for the text,icon and arrow of a menu item */ + float:left; /* To get the icons and text of sub elements side by side */ + padding-left:1px; + padding-right:1px; + +} +.DHTMLSuite_menuItem_sub_arrowShowSub{ /* Arrow div for sub elements (Right pointing arrow ) */ + position:absolute; /* Never change this one */ + background-image:url('../images/menu-item/menu-bar-right-arrow.gif'); /* Path relative to the css file */ + width:18px; + height:18px; + text-align:right; + right:0px; + background-repeat:no-repeat; /* No background repeat */ + background-position: center right; /* Position of arrow */ +} +head:first-child+body .DHTMLSuite_menuItem_sub_arrowShowSub { /* Transparent png for other browsers than IE6 */ + background-image: url('../images/menu-item/menu-bar-right-arrow.png'); /* Relative path to the arrow */ +} + +.DHTMLSuite_menuItem_separator_sub{ /* Separator of type "sub" */ + height:1px; /* Height of separator */ + margin-top:1px; /* Space above the separator */ + margin-bottom:1px; /* Space below the separator */ + margin-left:24px; /* left margin because we don't want the separator to cover the gradient */ + padding-right:3px; /* space at the right of the separator */ + background-color:#222; /* background color for the separator - blue */ +} + + diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/modal-message.css b/ext/dhtml-suite-for-applications/themes/tmw/css/modal-message.css index 8231760..e697172 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/modal-message.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/modal-message.css @@ -1,36 +1,36 @@ -/************************************************************************************************************ -* DHTML modal dialog box (CSS for the DHTMLSuite_modalMessage class) -* -* Created: August, 26th, 2006 -* @class Purpose of class: Display a modal dialog box on the screen. -* -* Css files used by this script: modal-message.css -* -* Update log: -* -************************************************************************************************************/ - -.DHTMLSuite_modalDialog_transparentDivs{ - filter:alpha(opacity=40); /* Transparency */ - opacity:0.4; /* Transparency */ - -moz-opacity:0.4; /* Transparency */ - background-color:#666; - z-index:1; - position:absolute; /* Always needed */ - z-index:100000; -} -.DHTMLSuite_modalDialog_contentDiv{ - border:3px solid #000; - padding:2px; - z-index:100002;/* Always needed */ - position:absolute; /* Always needed */ - background-color:#FFF; /* White background color for the message */ -} -.DHTMLSuite_modalDialog_contentDiv_shadow{ - z-index:100001;/* Always needed - to make it appear below the message */ - position:absolute; /* Always needed */ - background-color:#555; - filter:alpha(opacity=30); /* Transparency */ - opacity:0.3; /* Transparency */ - -moz-opacity:0.3;/* Transparency */ +/************************************************************************************************************ +* DHTML modal dialog box (CSS for the DHTMLSuite_modalMessage class) +* +* Created: August, 26th, 2006 +* @class Purpose of class: Display a modal dialog box on the screen. +* +* Css files used by this script: modal-message.css +* +* Update log: +* +************************************************************************************************************/ + +.DHTMLSuite_modalDialog_transparentDivs{ + filter:alpha(opacity=40); /* Transparency */ + opacity:0.4; /* Transparency */ + -moz-opacity:0.4; /* Transparency */ + background-color:#666; + z-index:1; + position:absolute; /* Always needed */ + z-index:100000; +} +.DHTMLSuite_modalDialog_contentDiv{ + border:3px solid #000; + padding:2px; + z-index:100002;/* Always needed */ + position:absolute; /* Always needed */ + background-color:#FFF; /* White background color for the message */ +} +.DHTMLSuite_modalDialog_contentDiv_shadow{ + z-index:100001;/* Always needed - to make it appear below the message */ + position:absolute; /* Always needed */ + background-color:#555; + filter:alpha(opacity=30); /* Transparency */ + opacity:0.3; /* Transparency */ + -moz-opacity:0.3;/* Transparency */ } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/pane-splitter.css b/ext/dhtml-suite-for-applications/themes/tmw/css/pane-splitter.css index f40d196..dd836fc 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/pane-splitter.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/pane-splitter.css @@ -1,493 +1,493 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, November 2222 - - CSS for the DHTMLSuite.paneSplitter class. - - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -/* Set the and element to full size and overflow to hidden -This is important for the script -*/ -html{ - width:100%; /* Full width and height */ - height:100%; - margin:0px; /* No space between browser edge and content */ - padding:0px; - overflow:hidden; /* Overflow: hide content, i.e. now scrollbars */ -} -body{ - width:100%; /* Full width and height */ - height:100%; - margin:0px; /* No space */ - padding:0px; - background-color:#666666; /* General background color, light blue */ -} -.DHTMLSuite_paneContent{ /* Pane content div */ - overflow:auto; /* IMPORTANT */ - position:relative; /* IMPORTANT */ - width:100%; - height:100%; - padding:0px; - margin:0px; -} - -.DHTMLSuite_pane{ /* Main div for a pane */ - overflow:hidden; /* Don't touch this one */ - - background-color:#FFF; /* White background color */ - - /* Pane borders - we only apply borders to the left and right side of the pane. The horzintal resize handler got a top and right border, so we don't need that on the pane. - You can override the css for a pane at the bottom of this css file, example: by applying css to #DHTMLSuite_pane_west - */ - border-left:1px solid #555555; /* Blue border - left */ - border-right:1px solid #555555; /* Blue border - right */ -} -.DHTMLSuite_paneHeader{ /* Pane header div - the title bar of a pane */ - overflow:hidden; /* Don't touch this one */ - color:#FFF; - height:23px; - line-height:22px; - background-image:url(../images/pane-splitter/pane-splitter-header-bg.png); /* Background image for the header - blue gradient. */ - background-repeat:repeat-x; /* Repeat background-image along the x-axis */ -} - - -.DHTMLSuite_paneContent .DHTMLSuite_paneContentInner{ /* A div inside .DHTMLSuite_paneContent. This is where the content is located. If you want to add some styling to the content of panes, this could be the place */ - padding:4px; /* "Air" */ -} - -/* START CSS FOR THE NAVIGATION TABS AT THE BOTTOM OF PANES */ - - -/* This is the css for the main div holding all the tabs */ - -.DHTMLSuite_paneTabs{ /* Div for the navigation tabs - this is the parent container for the tabs ( the bottom bar inside a pane ) */ - background-color:#666666; /* Blue color */ - height:24px; - line-height:24px; - border-top:1px solid #555555; /* Dark blue top border */ - padding-left:3px; /* Some "Air" before the first tab */ - padding-right:4px; /* Some "Air" at the right */ - position:relative; -} - -.DHTMLSuite_paneTabs div{ /* General rules for a tab */ - /* Deprecated display:block; /* Block level element */ - position:relative; /* Relative positioning since we have -1px on top - IMPORTANT!!! */ - margin-left:1px; /* 1 pixel space between each tab */ - font-size:0.9em; /* Font size: 12 pixels */ - line-height:120%; /* Font size * 1.2 */ - padding-left:10px; /* Left space inside tab - ps! Right space is added to the "a" tags below. */ - - top:-1px; /* -1px in order to cover the border above the tab - ( border is defined for .DHTMLSuite_paneTabs ) */ - overflow:hidden; /* Hide overflowing content - eventual */ - font-weight:bold; /* Bold font */ -} - -/* This css is there to fit tabs into the width of the pane. If you don't want this features, just remove them or implement alternative rules for individual panes. Example: - -#DHTMLSuite_pane_west .DHTMLSuite_paneTabs table{ - table-layout:auto; - width:auto; -} - -*/ - - -.DHTMLSuite_paneTabs table{ /* All tabs are placed inside a table */ - table-layout:fixed; - width:100%; -} -/* There is one - -The background of a tab is made out of two images. The left side of a tab is defined as background image for the DIV tag above. The right side is a background image for -the span tag. The span tag is absolute positioned at the right side of the div tag. - -*/ -.DHTMLSuite_paneTabs td{ - text-align:center; /* Center navigation tab text */ - text-overflow:ellipsis; - white-space:nowrap; -} - -.DHTMLSuite_paneTabs div{ - padding-right:5px; /* So that text inside the div(in the tag doesn't appear beneath the right side background image - background of the span tag */ -} -.DHTMLSuite_paneTabs div a{ /* Text links inside a tab - general css for the tabs*/ - display:block; /* Important */ - clear:both; - text-decoration:none; /* no underline */ - position:relative; - text-overflow:ellipsis; /* To get dotted lines at the right side of the text when it overflows it's boundaries */ - overflow:hidden; -} - -.DHTMLSuite_paneTabs .paneSplitterActiveTab{ /* Custom rules for active tabs */ - height:22px; - padding-top:0px; /* Padding-top - 1 pixel extra padding since we don't have border-top on active items */ - background-image:url(../images/pane-splitter/pane-splitter-tab-active-bg.png); /* The left part of a tab background - this should be wide enough to fill a cover a tab - typically 200 - 300 pixels wide */ - background-repeat:no-repeat; /* IMPORTANT */ -} - -.DHTMLSuite_paneTabs .paneSplitterActiveTab a{ /* The tag inside an active tab - A tab is a div with an a tag */ - padding-right:10px; /* Right space inside tab */ - padding-top:4px; - padding-bottom:4px; - height:22px; -} - -.DHTMLSuite_paneTabs .paneSplitterInactiveTab{ /* Custom rule for inactive tabs */ - border-top:1px solid #555555; /* A border on top - same border top color as for .DHTMLSuite_paneTabs (see above) - it's the border on top of inactive tabs */ - background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg.png); /* Left part of background image */ - background-repeat:no-repeat; /* No background repeat */ - height:21px; /* Height of inactive tabs - 1 pixel smaller than active tabs because of the top border - total height will be the same */ -} - -.DHTMLSuite_paneTabs .paneSplitterActiveTab a{ /* Tab text - active tabs */ - color:#222; /* Dark blue color */ -} -.DHTMLSuite_paneTabs .paneSplitterInactiveTab a{ /* Tab links - inactive tabs */ - color:#444; - line-height:17px; /* Height of tab */ - display:block; - padding-right:10px; /* Right space inside tab */ - padding-top:1px; /* Space at top - 1 pixel smaller than for the active tabs (.DHTMLSuite_paneTabs .paneSplitterActiveTab a) */ - padding-bottom:3px; - height:21px; -} - -.DHTMLSuite_paneTabs span{ /* The span tag which holds the background image for the right side of a tab */ - position:absolute; - right:0px; - top:0px; - height:22px; - width:14px; - display:block; - background-repeat:no-repeat; /* No background repeat */ - background-position:top right; /* Position background image at the right of the tag */ -} -.DHTMLSuite_paneTabs .paneSplitterInactiveTab span{ /* Background image inactive tab */ - background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg2.png); /* Right part of background image */ -} -.DHTMLSuite_paneTabs .paneSplitterActiveTab span{ /* Background image active tab */ - background-image:url(../images/pane-splitter/pane-splitter-tab-active-b2.png); /* The right part of a tab background (No transparency since this part overlaps the left part - see div declaration above )*/ -} - - - -/* for close button on tabs (batur) */ -.DHTMLSuite_paneTabs .paneSplitterInactiveTab span.closable{ /* Closable Background image inactive tab */ - background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg2-closable.png); /* Right part of background image */ -} - -.DHTMLSuite_paneTabs .paneSplitterInactiveTab span.closableOver{ /* Closable Background image inactive tab for the over state */ - background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg2-closable-over.png); /* Right part of background image */ -} - -.DHTMLSuite_paneTabs .paneSplitterActiveTab span.closable{ /* Closable Background image active tab */ - background-image:url(../images/pane-splitter/pane-splitter-tab-active-b2-closable.png); /* The right part of a tab background (No transparency since this part overlaps the left part - see div declaration above )*/ -} - -.DHTMLSuite_paneTabs .paneSplitterActiveTab span.closableOver{ /* Closable Background image active tab for the over state */ - background-image:url(../images/pane-splitter/pane-splitter-tab-active-b2-closable-over.png); /* The right part of a tab background (No transparency since this part overlaps the left part - see div declaration above )*/ -} - -/* end (batur) */ - - - -.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv{ /* Button container inside the header of a pane - parent element for the small buttons */ - padding:3px; -} - -.DHTMLSuite_paneHeader .paneTitle{ /* Title of pane - at the left of the header bar */ - padding-left:4px; /* Text indentation */ -} - - -.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv div, /* General rules for the small buttons inside a pane header */ -.DHTMLSuite_pane_collapsed_west .buttonDiv div, /* Also small buttons inside the box for collapsed panes */ -.DHTMLSuite_pane_collapsed_south .buttonDiv div, -.DHTMLSuite_pane_collapsed_east .buttonDiv div, -.DHTMLSuite_pane_collapsed_north .buttonDiv div -{ - background-repeat:no-repeat; /* No background repeat */ - width:15px; - height:15px; - background-position: center center; - cursor:pointer; /* "Hand" as cursor */ - -} - -.DHTMLSuite_pane_collapsed_west .buttonDiv div, /* Also small buttons inside the box for collapsed panes */ -.DHTMLSuite_pane_collapsed_south .buttonDiv div, -.DHTMLSuite_pane_collapsed_east .buttonDiv div, -.DHTMLSuite_pane_collapsed_north .buttonDiv div{ - margin:1px; -} - - -.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv div{ - float:right; /* Float items to the right - the buttons should be right aligned inside it's parent container(.DHTMLSuite_paneHeader_buttonDiv) */ -} - -.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv .closeButton,.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv .closeButtonOver{ /* Close button */ - background-image: url(../images/pane-splitter/pane-splitter-close.gif); /* Close button image */ - padding:1px; /* Same size as border for the over state */ -} - -.refreshButton, .refreshButtonOver{ - background-image: url(../images/pane-splitter/pane-splitter-refresh.gif); - padding:1px; /* Same size as border for the over state */ -} - -.collapseButtonHorizontal, .collapseButtonHorizontalOver{ /* collapse button (west and east pane) */ - background-image: url(../images/pane-splitter/pane-splitter-collapse.gif); - padding:1px; /* Same size as border for the over state */ -} - -.expandButtonHorizontal, .expandButtonHorizontalOver{ /* expand button (west and east pane) */ - background-image: url(../images/pane-splitter/pane-splitter-expand.gif); - padding:1px; /* Same size as border for the over state */ -} - -.collapseButtonVertical,.collapseButtonVerticalOver{ /* collapse button (north and south pane) */ - background-image: url(../images/pane-splitter/pane-splitter-collapse-v.gif); - padding:1px; /* Same size as border for the over state */ -} - -.expandButtonVertical,.expandButtonVerticalOver{ /* expand button (north and south pane) */ - background-image: url(../images/pane-splitter/pane-splitter-expand-v.gif); - padding:1px; /* Same size as border for the over state */ -} -.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv .closeButtonOver, -.collapseButtonHorizontalOver, -.expandButtonHorizontalOver, -.collapseButtonVerticalOver, -.refreshButtonOver, -.expandButtonVerticalOver{ /* Mouse over states - buttons */ - background-color:#444; - border:1px solid #666; - padding:0px; /* No padding since we have a border */ -} - -.DHTMLSuite_paneSplitter_horizontal{ /* Horizontal splitter resize handle */ - background-image:url('../images/pane-splitter/pane-splitter-resize-hor.png'); - background-repeat:no-repeat; - background-position: top center; - border-top:1px solid #555555; - cursor:n-resize; -} - -.DHTMLSuite_paneSplitter_horizontal_expInTitle{ /* Resize handler when expand collapse button is located inside title bar */ - background-image:url('../images/pane-splitter/pane-splitter-resize-hor2.png'); -} - - -.DHTMLSuite_paneSplitter_horizontal_noresize{ - background-image:url('../images/pane-splitter/pane-splitter-resize-hor-nd.png'); - background-repeat:no-repeat; - background-position: top center; - border-top:1px solid #555555; - cursor:default; - z-index:1; - -} -.DHTMLSuite_paneSplitter_vertical{ /* Vertical splitter resize handle */ - background-image:url('../images/pane-splitter/pane-splitter-resize-ver.png'); - background-repeat:no-repeat; - background-position: left center; - cursor:w-resize; -} -.DHTMLSuite_paneSplitter_vertical_expInTitle{ - background-image:url('../images/pane-splitter/pane-splitter-resize-ver2.png'); -} - -.DHTMLSuite_paneSplitter_vertical_noresize{ /* Vertical splitter resize handle */ - background-image:url('../images/pane-splitter/pane-splitter-resize-ver-nd.png'); - background-repeat:no-repeat; - background-position: left center; - cursor:default; - z-index:1; -} - - -.DHTMLSuite_resizeButtonLeft,.DHTMLSuite_resizeButtonRight{ - background-position:center center; - position:absolute; - left:0px; - top:50%; - height:50px; - margin-top:-25px; - width:100%; - background-repeat:no-repeat; - cursor:pointer; - opacity:0.5; - filter:alpha(opacity=50); -} - -.DHTMLSuite_collapseExpandOver{ - opacity:1; - filter:null; -} - -.DHTMLSuite_paneSplitter_vertical .DHTMLSuite_resizeButtonLeft{ - background-image:url('../images/pane-splitter/pane-splitter-coll-v-new.png'); -} - -.DHTMLSuite_paneSplitter_vertical .DHTMLSuite_resizeButtonRight{ - background-image:url('../images/pane-splitter/pane-splitter-coll-v-e-new.png'); -} - - - -.DHTMLSuite_resizeButtonUp,.DHTMLSuite_resizeButtonDown{ - background-position:center center; - position:absolute; - top:0px; - left:50%; - width:50px; - margin-left:-25px; - height:100%; - background-repeat:no-repeat; - cursor:pointer; - opacity:0.5; - filter:alpha(opacity=30); -} - -.DHTMLSuite_collapseExpandOver{ - opacity:1; - filter:null; -} - -.DHTMLSuite_paneSplitter_horizontal .DHTMLSuite_resizeButtonUp{ - background-image:url('../images/pane-splitter/pane-splitter-coll-h-new.png'); -} - -.DHTMLSuite_paneSplitter_horizontal .DHTMLSuite_resizeButtonDown{ - background-image:url('../images/pane-splitter/pane-splitter-coll-h-s-new.png'); -} - - - -.DHTMLSuite_paneSplitter_onResize{ /* Resize handle - resize in progress */ - background-color:#333; /* Just a gray background color - size is set automatically */ -} - -/* PANES IN COLLAPSED STATE */ -.DHTMLSuite_pane_collapsed_west,.DHTMLSuite_pane_collapsed_east{ /* Pane in collapsed state */ - background-color:#666666; - z-index:15000; - width:14px; - padding-bottom:1px; - -} -.DHTMLSuite_pane_collapsed_west{ - padding-left:4px; - left:0px; -} -.DHTMLSuite_pane_collapsed_east{ - padding-right:3px; -} -.DHTMLSuite_pane_collapsed_south,.DHTMLSuite_pane_collapsed_north{ /* Pane in collapsed state */ - background-color:#666666; - z-index:16000; - padding-left:3px; - padding-right:3px; - height:14px; - -} - -/* CSS for the panes in collapsed state */ -.DHTMLSuite_pane_collapsed_west{ - /* No border here because border is added to the left ot the center pane */ -} -.DHTMLSuite_pane_collapsed_south{ - padding-bottom:2px; -} -.DHTMLSuite_pane_collapsed_east{ - /* No border here because border is added to the right ot the center pane */ -} -.DHTMLSuite_pane_collapsed_north{ - padding-top:2px; - - border-bottom:1px solid #555555; /* Blue border */ -} - -/* .DHTMLSuite_pane_collapsedInner is the class name of the rectangular div for panes in collapsed state - the one with the border and the expand button */ -.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInnerOver, -.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInnerOver, -.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInnerOver, -.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInnerOver -{ - border:1px solid #555555; /* Blue border */ - - -} -/* Custom rules for west and east collapsed panes */ -.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInnerOver, -.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInnerOver -{ - width:12px; /* Width */ - float:none; -} - -/* Custom rules for north and south collapsed panes */ -.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInner, -.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInnerOver, -.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInnerOver -{ - height:12px; - margin-right:6px; -} - -.DHTMLSuite_pane_collapsedInnerOver{ /* Mouse over effect - panes in collapsed state */ - background-color:#555; /* Lighter blue background color */ - cursor:pointer; /* "Hand as a cursor */ -} - -/**** CUSTOM CSS FOR THE PANES - USER SPECIFIC - Usually, this part will be empty, and you will instead implement these rules in some other included css files */ - - -/** Custom css for each pane */ -#DHTMLSuite_pane_north{ /* Custom css for the north pane */ - background-color:#666666; /* Light blue background color */ - border-left:0px; -} -#DHTMLSuite_pane_west{ /* Custom css for the west pane */ - -} -#DHTMLSuite_pane_east{ /* Custom css for the east pane */ - -} -#DHTMLSuite_pane_south{ /* Custom css for the south pane */ - border-left:0px; -} -#DHTMLSuite_pane_center{ /* Custom css for the center pane */ - -} - -#DHTMLSuite_pane_south .DHTMLSuite_paneContent{ /* Css for pane content - the inner div where the content of a pane is located */ - font-size:0.9em; /* I want a smaller font for the CONTENT in the "south" pane */ -} - +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, November 2222 + + CSS for the DHTMLSuite.paneSplitter class. + + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +/* Set the and element to full size and overflow to hidden +This is important for the script +*/ +html{ + width:100%; /* Full width and height */ + height:100%; + margin:0px; /* No space between browser edge and content */ + padding:0px; + overflow:hidden; /* Overflow: hide content, i.e. now scrollbars */ +} +body{ + width:100%; /* Full width and height */ + height:100%; + margin:0px; /* No space */ + padding:0px; + background-color:#666666; /* General background color, light blue */ +} +.DHTMLSuite_paneContent{ /* Pane content div */ + overflow:auto; /* IMPORTANT */ + position:relative; /* IMPORTANT */ + width:100%; + height:100%; + padding:0px; + margin:0px; +} + +.DHTMLSuite_pane{ /* Main div for a pane */ + overflow:hidden; /* Don't touch this one */ + + background-color:#FFF; /* White background color */ + + /* Pane borders - we only apply borders to the left and right side of the pane. The horzintal resize handler got a top and right border, so we don't need that on the pane. + You can override the css for a pane at the bottom of this css file, example: by applying css to #DHTMLSuite_pane_west + */ + border-left:1px solid #555555; /* Blue border - left */ + border-right:1px solid #555555; /* Blue border - right */ +} +.DHTMLSuite_paneHeader{ /* Pane header div - the title bar of a pane */ + overflow:hidden; /* Don't touch this one */ + color:#FFF; + height:23px; + line-height:22px; + background-image:url(../images/pane-splitter/pane-splitter-header-bg.png); /* Background image for the header - blue gradient. */ + background-repeat:repeat-x; /* Repeat background-image along the x-axis */ +} + + +.DHTMLSuite_paneContent .DHTMLSuite_paneContentInner{ /* A div inside .DHTMLSuite_paneContent. This is where the content is located. If you want to add some styling to the content of panes, this could be the place */ + padding:4px; /* "Air" */ +} + +/* START CSS FOR THE NAVIGATION TABS AT THE BOTTOM OF PANES */ + + +/* This is the css for the main div holding all the tabs */ + +.DHTMLSuite_paneTabs{ /* Div for the navigation tabs - this is the parent container for the tabs ( the bottom bar inside a pane ) */ + background-color:#666666; /* Blue color */ + height:24px; + line-height:24px; + border-top:1px solid #555555; /* Dark blue top border */ + padding-left:3px; /* Some "Air" before the first tab */ + padding-right:4px; /* Some "Air" at the right */ + position:relative; +} + +.DHTMLSuite_paneTabs div{ /* General rules for a tab */ + /* Deprecated display:block; /* Block level element */ + position:relative; /* Relative positioning since we have -1px on top - IMPORTANT!!! */ + margin-left:1px; /* 1 pixel space between each tab */ + font-size:0.9em; /* Font size: 12 pixels */ + line-height:120%; /* Font size * 1.2 */ + padding-left:10px; /* Left space inside tab - ps! Right space is added to the "a" tags below. */ + + top:-1px; /* -1px in order to cover the border above the tab - ( border is defined for .DHTMLSuite_paneTabs ) */ + overflow:hidden; /* Hide overflowing content - eventual */ + font-weight:bold; /* Bold font */ +} + +/* This
      tag for each tab. The HTML for a tab looks like this: - - -
      - Tab text - -
      -
      css is there to fit tabs into the width of the pane. If you don't want this features, just remove them or implement alternative rules for individual panes. Example: + +#DHTMLSuite_pane_west .DHTMLSuite_paneTabs table{ + table-layout:auto; + width:auto; +} + +*/ + + +.DHTMLSuite_paneTabs table{ /* All tabs are placed inside a table */ + table-layout:fixed; + width:100%; +} +/* There is one + +The background of a tab is made out of two images. The left side of a tab is defined as background image for the DIV tag above. The right side is a background image for +the span tag. The span tag is absolute positioned at the right side of the div tag. + +*/ +.DHTMLSuite_paneTabs td{ + text-align:center; /* Center navigation tab text */ + text-overflow:ellipsis; + white-space:nowrap; +} + +.DHTMLSuite_paneTabs div{ + padding-right:5px; /* So that text inside the div(in the tag doesn't appear beneath the right side background image - background of the span tag */ +} +.DHTMLSuite_paneTabs div a{ /* Text links inside a tab - general css for the tabs*/ + display:block; /* Important */ + clear:both; + text-decoration:none; /* no underline */ + position:relative; + text-overflow:ellipsis; /* To get dotted lines at the right side of the text when it overflows it's boundaries */ + overflow:hidden; +} + +.DHTMLSuite_paneTabs .paneSplitterActiveTab{ /* Custom rules for active tabs */ + height:22px; + padding-top:0px; /* Padding-top - 1 pixel extra padding since we don't have border-top on active items */ + background-image:url(../images/pane-splitter/pane-splitter-tab-active-bg.png); /* The left part of a tab background - this should be wide enough to fill a cover a tab - typically 200 - 300 pixels wide */ + background-repeat:no-repeat; /* IMPORTANT */ +} + +.DHTMLSuite_paneTabs .paneSplitterActiveTab a{ /* The tag inside an active tab - A tab is a div with an a tag */ + padding-right:10px; /* Right space inside tab */ + padding-top:4px; + padding-bottom:4px; + height:22px; +} + +.DHTMLSuite_paneTabs .paneSplitterInactiveTab{ /* Custom rule for inactive tabs */ + border-top:1px solid #555555; /* A border on top - same border top color as for .DHTMLSuite_paneTabs (see above) - it's the border on top of inactive tabs */ + background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg.png); /* Left part of background image */ + background-repeat:no-repeat; /* No background repeat */ + height:21px; /* Height of inactive tabs - 1 pixel smaller than active tabs because of the top border - total height will be the same */ +} + +.DHTMLSuite_paneTabs .paneSplitterActiveTab a{ /* Tab text - active tabs */ + color:#222; /* Dark blue color */ +} +.DHTMLSuite_paneTabs .paneSplitterInactiveTab a{ /* Tab links - inactive tabs */ + color:#444; + line-height:17px; /* Height of tab */ + display:block; + padding-right:10px; /* Right space inside tab */ + padding-top:1px; /* Space at top - 1 pixel smaller than for the active tabs (.DHTMLSuite_paneTabs .paneSplitterActiveTab a) */ + padding-bottom:3px; + height:21px; +} + +.DHTMLSuite_paneTabs span{ /* The span tag which holds the background image for the right side of a tab */ + position:absolute; + right:0px; + top:0px; + height:22px; + width:14px; + display:block; + background-repeat:no-repeat; /* No background repeat */ + background-position:top right; /* Position background image at the right of the tag */ +} +.DHTMLSuite_paneTabs .paneSplitterInactiveTab span{ /* Background image inactive tab */ + background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg2.png); /* Right part of background image */ +} +.DHTMLSuite_paneTabs .paneSplitterActiveTab span{ /* Background image active tab */ + background-image:url(../images/pane-splitter/pane-splitter-tab-active-b2.png); /* The right part of a tab background (No transparency since this part overlaps the left part - see div declaration above )*/ +} + + + +/* for close button on tabs (batur) */ +.DHTMLSuite_paneTabs .paneSplitterInactiveTab span.closable{ /* Closable Background image inactive tab */ + background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg2-closable.png); /* Right part of background image */ +} + +.DHTMLSuite_paneTabs .paneSplitterInactiveTab span.closableOver{ /* Closable Background image inactive tab for the over state */ + background-image:url(../images/pane-splitter/pane-splitter-tab-inact-bg2-closable-over.png); /* Right part of background image */ +} + +.DHTMLSuite_paneTabs .paneSplitterActiveTab span.closable{ /* Closable Background image active tab */ + background-image:url(../images/pane-splitter/pane-splitter-tab-active-b2-closable.png); /* The right part of a tab background (No transparency since this part overlaps the left part - see div declaration above )*/ +} + +.DHTMLSuite_paneTabs .paneSplitterActiveTab span.closableOver{ /* Closable Background image active tab for the over state */ + background-image:url(../images/pane-splitter/pane-splitter-tab-active-b2-closable-over.png); /* The right part of a tab background (No transparency since this part overlaps the left part - see div declaration above )*/ +} + +/* end (batur) */ + + + +.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv{ /* Button container inside the header of a pane - parent element for the small buttons */ + padding:3px; +} + +.DHTMLSuite_paneHeader .paneTitle{ /* Title of pane - at the left of the header bar */ + padding-left:4px; /* Text indentation */ +} + + +.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv div, /* General rules for the small buttons inside a pane header */ +.DHTMLSuite_pane_collapsed_west .buttonDiv div, /* Also small buttons inside the box for collapsed panes */ +.DHTMLSuite_pane_collapsed_south .buttonDiv div, +.DHTMLSuite_pane_collapsed_east .buttonDiv div, +.DHTMLSuite_pane_collapsed_north .buttonDiv div +{ + background-repeat:no-repeat; /* No background repeat */ + width:15px; + height:15px; + background-position: center center; + cursor:pointer; /* "Hand" as cursor */ + +} + +.DHTMLSuite_pane_collapsed_west .buttonDiv div, /* Also small buttons inside the box for collapsed panes */ +.DHTMLSuite_pane_collapsed_south .buttonDiv div, +.DHTMLSuite_pane_collapsed_east .buttonDiv div, +.DHTMLSuite_pane_collapsed_north .buttonDiv div{ + margin:1px; +} + + +.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv div{ + float:right; /* Float items to the right - the buttons should be right aligned inside it's parent container(.DHTMLSuite_paneHeader_buttonDiv) */ +} + +.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv .closeButton,.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv .closeButtonOver{ /* Close button */ + background-image: url(../images/pane-splitter/pane-splitter-close.gif); /* Close button image */ + padding:1px; /* Same size as border for the over state */ +} + +.refreshButton, .refreshButtonOver{ + background-image: url(../images/pane-splitter/pane-splitter-refresh.gif); + padding:1px; /* Same size as border for the over state */ +} + +.collapseButtonHorizontal, .collapseButtonHorizontalOver{ /* collapse button (west and east pane) */ + background-image: url(../images/pane-splitter/pane-splitter-collapse.gif); + padding:1px; /* Same size as border for the over state */ +} + +.expandButtonHorizontal, .expandButtonHorizontalOver{ /* expand button (west and east pane) */ + background-image: url(../images/pane-splitter/pane-splitter-expand.gif); + padding:1px; /* Same size as border for the over state */ +} + +.collapseButtonVertical,.collapseButtonVerticalOver{ /* collapse button (north and south pane) */ + background-image: url(../images/pane-splitter/pane-splitter-collapse-v.gif); + padding:1px; /* Same size as border for the over state */ +} + +.expandButtonVertical,.expandButtonVerticalOver{ /* expand button (north and south pane) */ + background-image: url(../images/pane-splitter/pane-splitter-expand-v.gif); + padding:1px; /* Same size as border for the over state */ +} +.DHTMLSuite_paneHeader .DHTMLSuite_paneHeader_buttonDiv .closeButtonOver, +.collapseButtonHorizontalOver, +.expandButtonHorizontalOver, +.collapseButtonVerticalOver, +.refreshButtonOver, +.expandButtonVerticalOver{ /* Mouse over states - buttons */ + background-color:#444; + border:1px solid #666; + padding:0px; /* No padding since we have a border */ +} + +.DHTMLSuite_paneSplitter_horizontal{ /* Horizontal splitter resize handle */ + background-image:url('../images/pane-splitter/pane-splitter-resize-hor.png'); + background-repeat:no-repeat; + background-position: top center; + border-top:1px solid #555555; + cursor:n-resize; +} + +.DHTMLSuite_paneSplitter_horizontal_expInTitle{ /* Resize handler when expand collapse button is located inside title bar */ + background-image:url('../images/pane-splitter/pane-splitter-resize-hor2.png'); +} + + +.DHTMLSuite_paneSplitter_horizontal_noresize{ + background-image:url('../images/pane-splitter/pane-splitter-resize-hor-nd.png'); + background-repeat:no-repeat; + background-position: top center; + border-top:1px solid #555555; + cursor:default; + z-index:1; + +} +.DHTMLSuite_paneSplitter_vertical{ /* Vertical splitter resize handle */ + background-image:url('../images/pane-splitter/pane-splitter-resize-ver.png'); + background-repeat:no-repeat; + background-position: left center; + cursor:w-resize; +} +.DHTMLSuite_paneSplitter_vertical_expInTitle{ + background-image:url('../images/pane-splitter/pane-splitter-resize-ver2.png'); +} + +.DHTMLSuite_paneSplitter_vertical_noresize{ /* Vertical splitter resize handle */ + background-image:url('../images/pane-splitter/pane-splitter-resize-ver-nd.png'); + background-repeat:no-repeat; + background-position: left center; + cursor:default; + z-index:1; +} + + +.DHTMLSuite_resizeButtonLeft,.DHTMLSuite_resizeButtonRight{ + background-position:center center; + position:absolute; + left:0px; + top:50%; + height:50px; + margin-top:-25px; + width:100%; + background-repeat:no-repeat; + cursor:pointer; + opacity:0.5; + filter:alpha(opacity=50); +} + +.DHTMLSuite_collapseExpandOver{ + opacity:1; + filter:null; +} + +.DHTMLSuite_paneSplitter_vertical .DHTMLSuite_resizeButtonLeft{ + background-image:url('../images/pane-splitter/pane-splitter-coll-v-new.png'); +} + +.DHTMLSuite_paneSplitter_vertical .DHTMLSuite_resizeButtonRight{ + background-image:url('../images/pane-splitter/pane-splitter-coll-v-e-new.png'); +} + + + +.DHTMLSuite_resizeButtonUp,.DHTMLSuite_resizeButtonDown{ + background-position:center center; + position:absolute; + top:0px; + left:50%; + width:50px; + margin-left:-25px; + height:100%; + background-repeat:no-repeat; + cursor:pointer; + opacity:0.5; + filter:alpha(opacity=30); +} + +.DHTMLSuite_collapseExpandOver{ + opacity:1; + filter:null; +} + +.DHTMLSuite_paneSplitter_horizontal .DHTMLSuite_resizeButtonUp{ + background-image:url('../images/pane-splitter/pane-splitter-coll-h-new.png'); +} + +.DHTMLSuite_paneSplitter_horizontal .DHTMLSuite_resizeButtonDown{ + background-image:url('../images/pane-splitter/pane-splitter-coll-h-s-new.png'); +} + + + +.DHTMLSuite_paneSplitter_onResize{ /* Resize handle - resize in progress */ + background-color:#333; /* Just a gray background color - size is set automatically */ +} + +/* PANES IN COLLAPSED STATE */ +.DHTMLSuite_pane_collapsed_west,.DHTMLSuite_pane_collapsed_east{ /* Pane in collapsed state */ + background-color:#666666; + z-index:15000; + width:14px; + padding-bottom:1px; + +} +.DHTMLSuite_pane_collapsed_west{ + padding-left:4px; + left:0px; +} +.DHTMLSuite_pane_collapsed_east{ + padding-right:3px; +} +.DHTMLSuite_pane_collapsed_south,.DHTMLSuite_pane_collapsed_north{ /* Pane in collapsed state */ + background-color:#666666; + z-index:16000; + padding-left:3px; + padding-right:3px; + height:14px; + +} + +/* CSS for the panes in collapsed state */ +.DHTMLSuite_pane_collapsed_west{ + /* No border here because border is added to the left ot the center pane */ +} +.DHTMLSuite_pane_collapsed_south{ + padding-bottom:2px; +} +.DHTMLSuite_pane_collapsed_east{ + /* No border here because border is added to the right ot the center pane */ +} +.DHTMLSuite_pane_collapsed_north{ + padding-top:2px; + + border-bottom:1px solid #555555; /* Blue border */ +} + +/* .DHTMLSuite_pane_collapsedInner is the class name of the rectangular div for panes in collapsed state - the one with the border and the expand button */ +.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInnerOver, +.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInnerOver, +.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInnerOver, +.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInnerOver +{ + border:1px solid #555555; /* Blue border */ + + +} +/* Custom rules for west and east collapsed panes */ +.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_west .DHTMLSuite_pane_collapsedInnerOver, +.DHTMLSuite_pane_collapsed_east .DHTMLSuite_pane_collapsedInnerOver +{ + width:12px; /* Width */ + float:none; +} + +/* Custom rules for north and south collapsed panes */ +.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInner, +.DHTMLSuite_pane_collapsed_north .DHTMLSuite_pane_collapsedInnerOver, +.DHTMLSuite_pane_collapsed_south .DHTMLSuite_pane_collapsedInnerOver +{ + height:12px; + margin-right:6px; +} + +.DHTMLSuite_pane_collapsedInnerOver{ /* Mouse over effect - panes in collapsed state */ + background-color:#555; /* Lighter blue background color */ + cursor:pointer; /* "Hand as a cursor */ +} + +/**** CUSTOM CSS FOR THE PANES - USER SPECIFIC - Usually, this part will be empty, and you will instead implement these rules in some other included css files */ + + +/** Custom css for each pane */ +#DHTMLSuite_pane_north{ /* Custom css for the north pane */ + background-color:#666666; /* Light blue background color */ + border-left:0px; +} +#DHTMLSuite_pane_west{ /* Custom css for the west pane */ + +} +#DHTMLSuite_pane_east{ /* Custom css for the east pane */ + +} +#DHTMLSuite_pane_south{ /* Custom css for the south pane */ + border-left:0px; +} +#DHTMLSuite_pane_center{ /* Custom css for the center pane */ + +} + +#DHTMLSuite_pane_south .DHTMLSuite_paneContent{ /* Css for pane content - the inner div where the content of a pane is located */ + font-size:0.9em; /* I want a smaller font for the CONTENT in the "south" pane */ +} + diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/progress-bar.css b/ext/dhtml-suite-for-applications/themes/tmw/css/progress-bar.css index cf6a0db..f65bedd 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/progress-bar.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/progress-bar.css @@ -1,53 +1,53 @@ -#DHTMLSuite_progressPane{ - width:100%; - height:100%; - background-color:#FFF; - z-index:5000; - position:absolute; - left:0px; - top:0px; - -} -#DHTMLSuite_progressBar_bg{ - position:absolute; - left:50%; - top:50%; - width:300px; - height:20px; - border:1px solid #000; - background-color:#EEE; - margin-left:-150px; - margin-top:-20px; - text-align:center; -} -#DHTMLSuite_progressBar_outer{ - position:absolute; - left:0px; - top:0px; - width:0px; - height:100%; - overflow:hidden; -} - -#DHTMLSuite_progressBar{ - position:absolute; - left:0px; - top:0px; - width:300px; - background-color:#184EB8; - filter: Alpha(Opacity=0, FinishOpacity=100,Style=1,StartX=0, StartY=0, FinishX=200,FinishY=20) ; - height:100%; - z-index:5000; -} -#DHTMLSuite_progressBar_txt{ - color:#000; - z-index:10000; - width:100%; - height:100%; - left:0px; - top:0px; - position:absolute; - font-family:arial; - font-size:0.8em; - line-height:20px; /* Same as height of progress bar */ +#DHTMLSuite_progressPane{ + width:100%; + height:100%; + background-color:#FFF; + z-index:5000; + position:absolute; + left:0px; + top:0px; + +} +#DHTMLSuite_progressBar_bg{ + position:absolute; + left:50%; + top:50%; + width:300px; + height:20px; + border:1px solid #000; + background-color:#EEE; + margin-left:-150px; + margin-top:-20px; + text-align:center; +} +#DHTMLSuite_progressBar_outer{ + position:absolute; + left:0px; + top:0px; + width:0px; + height:100%; + overflow:hidden; +} + +#DHTMLSuite_progressBar{ + position:absolute; + left:0px; + top:0px; + width:300px; + background-color:#184EB8; + filter: Alpha(Opacity=0, FinishOpacity=100,Style=1,StartX=0, StartY=0, FinishX=200,FinishY=20) ; + height:100%; + z-index:5000; +} +#DHTMLSuite_progressBar_txt{ + color:#000; + z-index:10000; + width:100%; + height:100%; + left:0px; + top:0px; + position:absolute; + font-family:arial; + font-size:0.8em; + line-height:20px; /* Same as height of progress bar */ } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/resize.css b/ext/dhtml-suite-for-applications/themes/tmw/css/resize.css index 8e49200..1496192 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/resize.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/resize.css @@ -1,23 +1,23 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, January 2007 - - CSS for the DHTMLSuite.window class - - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -.DHTMLSuite_resize_handle{ /* The bar that is parent of the menu strip */ - position:absolute; - background-image:url(../images/resize/resize-handle-small-square.gif); - background-repeat:no-repeat; - width:7px; - height:7px; - z-index:10; - -} - +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, January 2007 + + CSS for the DHTMLSuite.window class + + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +.DHTMLSuite_resize_handle{ /* The bar that is parent of the menu strip */ + position:absolute; + background-image:url(../images/resize/resize-handle-small-square.gif); + background-repeat:no-repeat; + width:7px; + height:7px; + z-index:10; + +} + diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/slider.css b/ext/dhtml-suite-for-applications/themes/tmw/css/slider.css index 2285b6b..43eed68 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/slider.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/slider.css @@ -1,55 +1,55 @@ -/************************************************************************************************************ -* DHTML slider (CSS) -* -* Created: August, 25th, 2006 -* @class Purpose of class: Display a slider on a web page. -* -* Update log: -* -************************************************************************************************************/ - -.DHTMLSuite_slider_horizontal{ - border-top:1px solid #9d9c99; - border-left:1px solid #9d9c99; - border-bottom:1px solid #eee; - border-right:1px solid #eee; - background-color:#f0ede0; - height:3px; - position:absolute; - bottom:0px; - width:200px; - cursor:default; -} - -.DHTMLSuite_slider_vertical{ - border-left:1px solid #9d9c99; - border-bottom:1px solid #9d9c99; - border-right:1px solid #eee; - border-top:1px solid #eee; - background-color:#f0ede0; - width:3px; - position:absolute; - bottom:0px; - height:200px; - margin-left:1px; - cursor:default; -} -/* Small lines indicating steps on the slider */ -.DHTMLSuite_smallLines_vertical{ /* Vertical lines */ - border-top:1px solid #9d9c99; - border-left:1px solid #9d9c99; - border-bottom:1px solid #eee; - border-right:1px solid #eee; - width:0px; - height:5px; - cursor:default; -} -.DHTMLSuite_smallLines_horizontal{ /* Horizontal lines */ - border-top:1px solid #9d9c99; - border-left:1px solid #9d9c99; - border-bottom:1px solid #eee; - border-right:1px solid #eee; - width:5px; - height:1px; - cursor:default; +/************************************************************************************************************ +* DHTML slider (CSS) +* +* Created: August, 25th, 2006 +* @class Purpose of class: Display a slider on a web page. +* +* Update log: +* +************************************************************************************************************/ + +.DHTMLSuite_slider_horizontal{ + border-top:1px solid #9d9c99; + border-left:1px solid #9d9c99; + border-bottom:1px solid #eee; + border-right:1px solid #eee; + background-color:#f0ede0; + height:3px; + position:absolute; + bottom:0px; + width:200px; + cursor:default; +} + +.DHTMLSuite_slider_vertical{ + border-left:1px solid #9d9c99; + border-bottom:1px solid #9d9c99; + border-right:1px solid #eee; + border-top:1px solid #eee; + background-color:#f0ede0; + width:3px; + position:absolute; + bottom:0px; + height:200px; + margin-left:1px; + cursor:default; +} +/* Small lines indicating steps on the slider */ +.DHTMLSuite_smallLines_vertical{ /* Vertical lines */ + border-top:1px solid #9d9c99; + border-left:1px solid #9d9c99; + border-bottom:1px solid #eee; + border-right:1px solid #eee; + width:0px; + height:5px; + cursor:default; +} +.DHTMLSuite_smallLines_horizontal{ /* Horizontal lines */ + border-top:1px solid #9d9c99; + border-left:1px solid #9d9c99; + border-bottom:1px solid #eee; + border-right:1px solid #eee; + width:5px; + height:1px; + cursor:default; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/tab-view.css b/ext/dhtml-suite-for-applications/themes/tmw/css/tab-view.css index 347f69a..a519085 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/tab-view.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/tab-view.css @@ -1,74 +1,74 @@ -/************************************************************************************************************ -* Tab view class (CSS for the DHTMLSuite_tabView class) -* -* Created: August, 21st, 2006 -* Purpose of class: Tab view class - transfors plain HTML into tabable layers. -* -* -* Update log: -* -************************************************************************************************************/ -/* The tab widget */ -.DHTMLSuite_tabWidget{ - margin-bottom:5px; /* A little space below the tab pane */ -} - -.DHTMLSuite_tabContainer{ - height:21px; /* Height of tabs */ - border-bottom:1px solid #919b9c; -} -.DHTMLSuite_aTab{ - border-left:1px solid #919b9c; - border-right:1px solid #919b9c; - border-bottom:1px solid #919b9c; - font-family: Trebuchet MS, Lucida Sans Unicode, Arial, sans-serif; - padding:5px; - background-color:#FCFCFE; - -} -.DHTMLSuite_tabContainer DIV{ - float:left; - height:100%; /* Height of tabs */ - padding-left:3px; - vertical-align:middle; - background-repeat:no-repeat; - background-position:bottom left; - cursor:pointer; - position:relative; - bottom:-1px; - margin-left:0px; - margin-right:0px; - -} -.DHTMLSuite_tabContainer .tabActive{ - margin-left:0px; - margin-right:0px; - z-index:10; -} -.DHTMLSuite_tabContainer .tabInactive{ - margin-left:0px; - margin-right:0px; - z-index:1; -} - -.DHTMLSuite_tabContainer .inactiveTabOver{ - margin-left:0px; - margin-right:0px; -} -.DHTMLSuite_tabContainer span{ - font-family:arial; - vertical-align:top; - font-size:11px; - padding-left:3px; - padding-right:3px; - line-height:21px; - float:left; -} -.DHTMLSuite_tabContainer .tabActive span{ - padding-bottom:1px; - line-height:20px; -} - -.DHTMLSuite_tabContainer img{ - float:left; +/************************************************************************************************************ +* Tab view class (CSS for the DHTMLSuite_tabView class) +* +* Created: August, 21st, 2006 +* Purpose of class: Tab view class - transfors plain HTML into tabable layers. +* +* +* Update log: +* +************************************************************************************************************/ +/* The tab widget */ +.DHTMLSuite_tabWidget{ + margin-bottom:5px; /* A little space below the tab pane */ +} + +.DHTMLSuite_tabContainer{ + height:21px; /* Height of tabs */ + border-bottom:1px solid #919b9c; +} +.DHTMLSuite_aTab{ + border-left:1px solid #919b9c; + border-right:1px solid #919b9c; + border-bottom:1px solid #919b9c; + font-family: Trebuchet MS, Lucida Sans Unicode, Arial, sans-serif; + padding:5px; + background-color:#FCFCFE; + +} +.DHTMLSuite_tabContainer DIV{ + float:left; + height:100%; /* Height of tabs */ + padding-left:3px; + vertical-align:middle; + background-repeat:no-repeat; + background-position:bottom left; + cursor:pointer; + position:relative; + bottom:-1px; + margin-left:0px; + margin-right:0px; + +} +.DHTMLSuite_tabContainer .tabActive{ + margin-left:0px; + margin-right:0px; + z-index:10; +} +.DHTMLSuite_tabContainer .tabInactive{ + margin-left:0px; + margin-right:0px; + z-index:1; +} + +.DHTMLSuite_tabContainer .inactiveTabOver{ + margin-left:0px; + margin-right:0px; +} +.DHTMLSuite_tabContainer span{ + font-family:arial; + vertical-align:top; + font-size:11px; + padding-left:3px; + padding-right:3px; + line-height:21px; + float:left; +} +.DHTMLSuite_tabContainer .tabActive span{ + padding-bottom:1px; + line-height:20px; +} + +.DHTMLSuite_tabContainer img{ + float:left; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget-page-handler.css b/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget-page-handler.css index 043e1a8..e751b98 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget-page-handler.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget-page-handler.css @@ -1,49 +1,49 @@ -.DHTMLSuite_tableWidgetPageHandler_mainDiv{ /* parent div */ - -} - -.DHTMLSuite_tableWidgetPageHandler_mainDiv a{ - color:#333; -} - -.DHTMLSuite_tableWidgetPageHandler_mainDiv span{ /* There's a in front and behind every page links, example: [1] */ - padding-left:2px; - padding-right:2px; -} -.DHTMLSuite_tableWidgetPageHandler_mainDiv span.DHTMLSuite_pageHandler_lastLink{ - padding-left:5px; -} -span.DHTMLSuite_pageHandler_firstLink{ - padding-left:0px; - padding-right:7px; -} -span.DHTMLSuite_pageHandler_previousLink{ - padding-left:0px; -} - -.DHTMLSuite_tableWidgetPageHandler_result{ /* Result div : Result: 1 to 10 of 51 */ - font-size:0.9em; /* Slightly smaller font */ - -} - -/* Page list div : Previous [1] [2] [3] Next */ -.DHTMLSuite_tableWidgetPageHandler_pageList{ - -} - -.DHTMLSuite_tableWidgetPageHandler_pageList .previousLinkDisabled,.DHTMLSuite_tableWidgetPageHandler_pageList .nextLinkDisabled{ /* Disabled previous link and disabled next link */ - color:#999; - cursor:default; - -} -.DHTMLSuite_tableWidgetPageHandler_pageList .DHTMLSuite_tableWidgetPageHandler_activePage{ /* Active page number */ - color:#F00; -} -.DHTMLSuite_tableWidgetPageHandler_pageList .DHTMLSuite_tableWidgetPageHandler_inactivePage{ /* Active page number */ - -} -.DHTMLSuite_tableWidgetPageHandler_pageList .DHTMLSuite_tableWidgetPageHandler_resultDisplay{ /* Div displaying info about dataset - Result: 1 to 10 of 51 */ - - - +.DHTMLSuite_tableWidgetPageHandler_mainDiv{ /* parent div */ + +} + +.DHTMLSuite_tableWidgetPageHandler_mainDiv a{ + color:#333; +} + +.DHTMLSuite_tableWidgetPageHandler_mainDiv span{ /* There's a in front and behind every page links, example: [1] */ + padding-left:2px; + padding-right:2px; +} +.DHTMLSuite_tableWidgetPageHandler_mainDiv span.DHTMLSuite_pageHandler_lastLink{ + padding-left:5px; +} +span.DHTMLSuite_pageHandler_firstLink{ + padding-left:0px; + padding-right:7px; +} +span.DHTMLSuite_pageHandler_previousLink{ + padding-left:0px; +} + +.DHTMLSuite_tableWidgetPageHandler_result{ /* Result div : Result: 1 to 10 of 51 */ + font-size:0.9em; /* Slightly smaller font */ + +} + +/* Page list div : Previous [1] [2] [3] Next */ +.DHTMLSuite_tableWidgetPageHandler_pageList{ + +} + +.DHTMLSuite_tableWidgetPageHandler_pageList .previousLinkDisabled,.DHTMLSuite_tableWidgetPageHandler_pageList .nextLinkDisabled{ /* Disabled previous link and disabled next link */ + color:#999; + cursor:default; + +} +.DHTMLSuite_tableWidgetPageHandler_pageList .DHTMLSuite_tableWidgetPageHandler_activePage{ /* Active page number */ + color:#F00; +} +.DHTMLSuite_tableWidgetPageHandler_pageList .DHTMLSuite_tableWidgetPageHandler_inactivePage{ /* Active page number */ + +} +.DHTMLSuite_tableWidgetPageHandler_pageList .DHTMLSuite_tableWidgetPageHandler_resultDisplay{ /* Div displaying info about dataset - Result: 1 to 10 of 51 */ + + + } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget.css b/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget.css index f5c8b3c..7f0fc70 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/table-widget.css @@ -1,91 +1,91 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, August 2006 - - CSS for the DHTMLsuite_tableWidget class. - - Terms of use: - Look at the terms of use at http://www.dhtmlgoodies.com/index.html?page=termsOfUse - - Thank you! - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -.DHTMLSuite_tableWidget_headerCell,.DHTMLSuite_tableWigdet_headerCellOver,.DHTMLSuite_tableWigdet_headerCellDown{ /* General rules for both standard column header and mouse on header of sortable columns */ - cursor:pointer; - border-bottom:3px solid #C5C2B2; - border-right:1px solid #ACA899; - - border-left:1px solid #FFF; - background-color: #ECE9D8; -} - -.DHTMLSuite_tableWidget_headerCell{ /* Standard column header */ - border-top:2px solid #ECE9D8; - -} - -.DHTMLSuite_tableWigdet_headerCellOver{ /* Rollover on sortable column header */ - border-top:2px solid #FFC83C; -} -.DHTMLSuite_tableWidget tbody .DHTMLSuite_tableWidget_dataRollOver{ /* Rollover style on mouse over (Data) */ - background-color:#EEE; /* No mouseover color in this example - specify another color if you want this */ -} - -.DHTMLSuite_tableWigdet_headerCellDown{ - border-top:2px solid #FFC83C; - background-color:#DBD8C5; - border-left:1px solid #ACA899; - border-right:1px solid #FFF; -} -.DHTMLSuite_tableWidget td{ - margin:0px; - padding:2px; - border-bottom:1px solid #EAE9E1; /* Border bottom of table data cells */ - -} -.DHTMLSuite_tableWidget{ - font-family:arial; - font-size:12px; - width:400px; -} - -/* Div around the table */ -div.DHTMLSuite_widget_tableDiv { - border:1px solid #ACA899; /* Border around entire widget */ - height: 200px; - overflow:auto; - overflow-y:auto; - overflow:-moz-scrollbars-vertical; - width:400px; -} - -html>body div.DHTMLSuite_widget_tableDiv { - overflow: auto; /* This value will be replaced with "hidden" for non-safari browsers. Ie. will also have overflow-x:hidden in order to prevent a horizontal scrollbar */ - width:400px; -} -.DHTMLSuite_tableWidget tbody{ - background-color:#FFF; -} -.DHTMLSuite_tableWidget thead{ - position:relative; -} -.DHTMLSuite_tableWidget thead tr{ - position:relative; - top:0px; - bottom:0px; -} -.DHTMLSuite_tableWidget .DHTMLSuite_scrollingContent{ - overflow-y:auto; - overflow:-moz-scrollbars-vertical; - width:100%; - -} -.DHTMLSuite_tableWidget .DHTMLSuite_tableWidget_MSIESPACER{ - width:16px; - overflowX:hidden; +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, August 2006 + + CSS for the DHTMLsuite_tableWidget class. + + Terms of use: + Look at the terms of use at http://www.dhtmlgoodies.com/index.html?page=termsOfUse + + Thank you! + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +.DHTMLSuite_tableWidget_headerCell,.DHTMLSuite_tableWigdet_headerCellOver,.DHTMLSuite_tableWigdet_headerCellDown{ /* General rules for both standard column header and mouse on header of sortable columns */ + cursor:pointer; + border-bottom:3px solid #C5C2B2; + border-right:1px solid #ACA899; + + border-left:1px solid #FFF; + background-color: #ECE9D8; +} + +.DHTMLSuite_tableWidget_headerCell{ /* Standard column header */ + border-top:2px solid #ECE9D8; + +} + +.DHTMLSuite_tableWigdet_headerCellOver{ /* Rollover on sortable column header */ + border-top:2px solid #FFC83C; +} +.DHTMLSuite_tableWidget tbody .DHTMLSuite_tableWidget_dataRollOver{ /* Rollover style on mouse over (Data) */ + background-color:#EEE; /* No mouseover color in this example - specify another color if you want this */ +} + +.DHTMLSuite_tableWigdet_headerCellDown{ + border-top:2px solid #FFC83C; + background-color:#DBD8C5; + border-left:1px solid #ACA899; + border-right:1px solid #FFF; +} +.DHTMLSuite_tableWidget td{ + margin:0px; + padding:2px; + border-bottom:1px solid #EAE9E1; /* Border bottom of table data cells */ + +} +.DHTMLSuite_tableWidget{ + font-family:arial; + font-size:12px; + width:400px; +} + +/* Div around the table */ +div.DHTMLSuite_widget_tableDiv { + border:1px solid #ACA899; /* Border around entire widget */ + height: 200px; + overflow:auto; + overflow-y:auto; + overflow:-moz-scrollbars-vertical; + width:400px; +} + +html>body div.DHTMLSuite_widget_tableDiv { + overflow: auto; /* This value will be replaced with "hidden" for non-safari browsers. Ie. will also have overflow-x:hidden in order to prevent a horizontal scrollbar */ + width:400px; +} +.DHTMLSuite_tableWidget tbody{ + background-color:#FFF; +} +.DHTMLSuite_tableWidget thead{ + position:relative; +} +.DHTMLSuite_tableWidget thead tr{ + position:relative; + top:0px; + bottom:0px; +} +.DHTMLSuite_tableWidget .DHTMLSuite_scrollingContent{ + overflow-y:auto; + overflow:-moz-scrollbars-vertical; + width:100%; + +} +.DHTMLSuite_tableWidget .DHTMLSuite_tableWidget_MSIESPACER{ + width:16px; + overflowX:hidden; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/text-edit.css b/ext/dhtml-suite-for-applications/themes/tmw/css/text-edit.css index 2805daf..7e0d1b7 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/text-edit.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/text-edit.css @@ -1,18 +1,18 @@ -.DHTMLSuite_textEdit_label{ /* label */ - background-color:#316ac5; - color:#FFF; -} -.DHTMLSuite_textEdit_select,.DHTMLSuite_textEdit_input{ - width:200px; - font-size:11px; - line-height:12px; - margin:0px; - padding:0px; -} - -.DHTMLSuite_textEdit_input{ - height:12px; -} -.DHTMLSuite_textEdit_select{ - height:18px; +.DHTMLSuite_textEdit_label{ /* label */ + background-color:#316ac5; + color:#FFF; +} +.DHTMLSuite_textEdit_select,.DHTMLSuite_textEdit_input{ + width:200px; + font-size:11px; + line-height:12px; + margin:0px; + padding:0px; +} + +.DHTMLSuite_textEdit_input{ + height:12px; +} +.DHTMLSuite_textEdit_select{ + height:18px; } \ No newline at end of file diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/window-theme-windows.css b/ext/dhtml-suite-for-applications/themes/tmw/css/window-theme-windows.css index e2ab8c4..cb78a0b 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/window-theme-windows.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/window-theme-windows.css @@ -1,223 +1,223 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, January 2007 - - CSS for the DHTMLSuite.window class - - - www.dhtmlgoodies.com - Alf Magne Kalleland - -************************************************************************************************************/ - -.DHTMLSuite_window{ /* The bar that is parent of the menu strip */ - background-color:#E2E2E2; - border:2px solid #555; - border-top:1px solid #252525; - width:330px; - height:200px; - overflow:hidden; - top:0px; - left:0px; - z-index:1000; - padding-right:0px; -} - -.DHTMLSuite_windowInnerDiv{ /* This div is the parent parent element of window elements such as tabs, content and status bar, i.e. the primary main parent element for a window */ - position:relative; - background-color:#E2E2E2; - top:0px; - left:0px; - width:100%; - height:100%; - background-color:#E2E2E2; -} - -.DHTMLSuite_windowTitleBar{ /* Title bar of window */ - background-image:url(../images/window-theme-windows/window_titlebar.png); - background-repeat:repeat-x; - height:16px; - position:relative; /* IMPORTANT */ - - -} -.DHTMLSuite_windowTitleInTitleBar{ /* The title text in the title bar */ - padding:1px; - padding-left:5px; - font-size:10px; - color:white; - font-weight:bold; - font-family:arial; -} -.DHTMLSuite_windowButtonDiv{ /* Div for the buttons in the title bar */ - position:absolute; - right:1px; - top:0px; - width:40px; - cursor:default; -} - -.DHTMLSuite_windowButtonDiv div{ - float:right; - position:relative; -} -/* General button rules */ -.DHTMLSuite_windowMinimizeButton,.DHTMLSuite_windowCloseButton,.DHTMLSuite_windowMaximizeButton{ - background-repeat:no-repeat; - background-position:center center; - padding:1px; - width:13px; - height:13px; - -} -/* Close button */ -.DHTMLSuite_windowCloseButton{ - background-image:url(../images/window-theme-windows/window-close.gif); -} -.DHTMLSuite_windowCloseButtonOver{ - background-image:url(../images/window-theme-windows/window-close-over.gif); - cursor:default; -} - -/* Minimize button */ -.DHTMLSuite_windowMinimizeButton{ - background-image:url(../images/window-theme-windows/window-minimize.gif); -} -DIV.DHTMLSuite_windowMinimizeButton.DHTMLSuite_windowMinimizeButtonOver{ - background-image:url(../images/window-theme-windows/window-minimize-over.gif); - cursor:default; -} -/* Minimize button */ -.DHTMLSuite_windowMaximizeButton{ - background-image:url(../images/window-theme-windows/window-maximize.gif); -} -DIV.DHTMLSuite_windowMaximizeButton.DHTMLSuite_windowMaximizeButtonOver{ - background-image:url(../images/window-theme-windows/window-maximize-over.gif); - cursor:default; -} - -/* CSS for the tab row */ - -.DHTMLSuite_windowTabRow{ - background-color:#B2B2B2; - padding-top:0px; - height:16px; - border-top:1px solid #ACA899; - padding-left:5px; - position:relative; - width:1900px; - z-index:500; /* IMPORTANT */ - -} -.DHTMLSuite_windowTabRow td{ - text-overflow:ellipsis; - white-space:nowrap; - font-weight:bold; -} -.DHTMLSuite_windowATab{ - float:left; - background-position:bottom right; - background-repeat:no-repeat; - height:16px; - cursor:default; - font-size:10px; - line-height:15px; - font-family:arial; - overflow:hidden; -} - -.DHTMLSuite_windowATabInnerDiv{ - background-repeat:no-repeat; - background-position:bottom left; - height:15px; - position:relative; - z-index:10000; - padding-left:5px; - margin-right:19px; /* Width of the right side image */ - padding-right:4px; -} - -.DHTMLSuite_windowActiveTabCell{ /* Active tab - td tag */ - background-image:url('../images/window-theme-windows/tab-active-right.gif'); - position:relative; - bottom:-1px; -} -head:first-child+body .DHTMLSuite_windowActiveTabCell { /* Transparent png for other browsers than IE6 */ - background-image:url('../images/window-theme-windows/tab-active-right.png'); -} - - -.DHTMLSuite_windowInactiveTabCell{ /* Inactive tab, '; - $out .= $this->newline; - } - - // Is there a table heading to display? - if (count($this->heading) > 0) - { - $out .= $this->template['heading_row_start']; - $out .= $this->newline; - - foreach($this->heading as $heading) - { - $out .= $this->template['heading_cell_start']; - $out .= $heading; - $out .= $this->template['heading_cell_end']; - } - - $out .= $this->template['heading_row_end']; - $out .= $this->newline; - } - - // Build the table rows - if (count($this->rows) > 0) - { - $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) - { - $out .= $this->template['cell_'.$name.'start']; - - if ($cell === "") - { - $out .= $this->empty_cells; - } - else - { - $out .= $cell; - } - - $out .= $this->template['cell_'.$name.'end']; - } - - $out .= $this->template['row_'.$name.'end']; - $out .= $this->newline; - } - } - - $out .= $this->template['table_close']; - - 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 = $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[] = $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 ( ! is_array($row)) - { - $this->rows[] = $data; - break; - } - - // 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 = $row; - } - else - { - $this->rows[] = $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','heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', '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' => '
      tag for each tab. The HTML for a tab looks like this: + + +
      + Tab text + +
      +
      tag */ - background-image:url('../images/window-theme-windows/tab-inactive-right.gif'); - position:relative; - color:#4B4B4B; - line-height:16px; -} - -head:first-child+body .DHTMLSuite_windowInactiveTabCell { /* Transparent png for other browsers than IE6 */ - background-image:url('../images/window-theme-windows/tab-inactive-right.png'); -} - - -.DHTMLSuite_windowActiveTabCellContent{ /* Active tab - inner div */ - background-image:url('../images/window-theme-windows/tab-active-left.gif'); - height:14px; /* These three lines are added in order to make the text of active tab appear on line with text of inactive tabs */ - line-height:14px; - padding-bottom:2px; - padding-top:1px; -} -head:first-child+body .DHTMLSuite_windowActiveTabCellContent { /* Transparent png for other browsers than IE6 */ - background-image:url('../images/window-theme-windows/tab-active-left.png'); - padding-top:0px; -} - - -.DHTMLSuite_windowInactiveTabCellContent{ - background-image:url('../images/window-theme-windows/tab-inactive-left.gif'); - padding-bottom:1px; -} - -head:first-child+body .DHTMLSuite_windowInactiveTabCellContent { /* Transparent png for other browsers than IE6 */ - background-image:url('../images/window-theme-windows/tab-inactive-left.png'); -} - - -.DHTMLSuite_windowContent{ - overflow:auto; - background-color:#E2E2E2; - margin-left:0px; - margin-right:0px; - border-top:1px solid #FFF; - padding-bottom:1px; - position:relative; - font-size:0.9em; -} - -.DHTMLSuite_windowContent .DHTMLSuite_windowContentInner{ /* Div for each of the tab content divs */ - padding:1px; -} -/* Start css for window status bar */ -.DHTMLSuite_windowStatusBar{ - height:14px; - border-top:1px solid #ACA899; - background-color:#E2E2E2; - position:relative; - overflow:hidden; -} -.DHTMLSuite_windowStatusBarText{ /* Text inside status bar */ - font-size:11px; - line-height:13px; - padding:1px; -} - -.DHTMLSuite_windowResizeHandle{ - background-image:url('../images/window-theme-windows/resize-handle-bottom-right.gif'); - background-repeat:no-repeat; - position:absolute; - bottom:1px; - right:1px; - width:14px; - height:14px; - border-left:1px solid #ACA899; -} +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, January 2007 + + CSS for the DHTMLSuite.window class + + + www.dhtmlgoodies.com + Alf Magne Kalleland + +************************************************************************************************************/ + +.DHTMLSuite_window{ /* The bar that is parent of the menu strip */ + background-color:#E2E2E2; + border:2px solid #555; + border-top:1px solid #252525; + width:330px; + height:200px; + overflow:hidden; + top:0px; + left:0px; + z-index:1000; + padding-right:0px; +} + +.DHTMLSuite_windowInnerDiv{ /* This div is the parent parent element of window elements such as tabs, content and status bar, i.e. the primary main parent element for a window */ + position:relative; + background-color:#E2E2E2; + top:0px; + left:0px; + width:100%; + height:100%; + background-color:#E2E2E2; +} + +.DHTMLSuite_windowTitleBar{ /* Title bar of window */ + background-image:url(../images/window-theme-windows/window_titlebar.png); + background-repeat:repeat-x; + height:16px; + position:relative; /* IMPORTANT */ + + +} +.DHTMLSuite_windowTitleInTitleBar{ /* The title text in the title bar */ + padding:1px; + padding-left:5px; + font-size:10px; + color:white; + font-weight:bold; + font-family:arial; +} +.DHTMLSuite_windowButtonDiv{ /* Div for the buttons in the title bar */ + position:absolute; + right:1px; + top:0px; + width:40px; + cursor:default; +} + +.DHTMLSuite_windowButtonDiv div{ + float:right; + position:relative; +} +/* General button rules */ +.DHTMLSuite_windowMinimizeButton,.DHTMLSuite_windowCloseButton,.DHTMLSuite_windowMaximizeButton{ + background-repeat:no-repeat; + background-position:center center; + padding:1px; + width:13px; + height:13px; + +} +/* Close button */ +.DHTMLSuite_windowCloseButton{ + background-image:url(../images/window-theme-windows/window-close.gif); +} +.DHTMLSuite_windowCloseButtonOver{ + background-image:url(../images/window-theme-windows/window-close-over.gif); + cursor:default; +} + +/* Minimize button */ +.DHTMLSuite_windowMinimizeButton{ + background-image:url(../images/window-theme-windows/window-minimize.gif); +} +DIV.DHTMLSuite_windowMinimizeButton.DHTMLSuite_windowMinimizeButtonOver{ + background-image:url(../images/window-theme-windows/window-minimize-over.gif); + cursor:default; +} +/* Minimize button */ +.DHTMLSuite_windowMaximizeButton{ + background-image:url(../images/window-theme-windows/window-maximize.gif); +} +DIV.DHTMLSuite_windowMaximizeButton.DHTMLSuite_windowMaximizeButtonOver{ + background-image:url(../images/window-theme-windows/window-maximize-over.gif); + cursor:default; +} + +/* CSS for the tab row */ + +.DHTMLSuite_windowTabRow{ + background-color:#B2B2B2; + padding-top:0px; + height:16px; + border-top:1px solid #ACA899; + padding-left:5px; + position:relative; + width:1900px; + z-index:500; /* IMPORTANT */ + +} +.DHTMLSuite_windowTabRow td{ + text-overflow:ellipsis; + white-space:nowrap; + font-weight:bold; +} +.DHTMLSuite_windowATab{ + float:left; + background-position:bottom right; + background-repeat:no-repeat; + height:16px; + cursor:default; + font-size:10px; + line-height:15px; + font-family:arial; + overflow:hidden; +} + +.DHTMLSuite_windowATabInnerDiv{ + background-repeat:no-repeat; + background-position:bottom left; + height:15px; + position:relative; + z-index:10000; + padding-left:5px; + margin-right:19px; /* Width of the right side image */ + padding-right:4px; +} + +.DHTMLSuite_windowActiveTabCell{ /* Active tab - td tag */ + background-image:url('../images/window-theme-windows/tab-active-right.gif'); + position:relative; + bottom:-1px; +} +head:first-child+body .DHTMLSuite_windowActiveTabCell { /* Transparent png for other browsers than IE6 */ + background-image:url('../images/window-theme-windows/tab-active-right.png'); +} + + +.DHTMLSuite_windowInactiveTabCell{ /* Inactive tab, tag */ + background-image:url('../images/window-theme-windows/tab-inactive-right.gif'); + position:relative; + color:#4B4B4B; + line-height:16px; +} + +head:first-child+body .DHTMLSuite_windowInactiveTabCell { /* Transparent png for other browsers than IE6 */ + background-image:url('../images/window-theme-windows/tab-inactive-right.png'); +} + + +.DHTMLSuite_windowActiveTabCellContent{ /* Active tab - inner div */ + background-image:url('../images/window-theme-windows/tab-active-left.gif'); + height:14px; /* These three lines are added in order to make the text of active tab appear on line with text of inactive tabs */ + line-height:14px; + padding-bottom:2px; + padding-top:1px; +} +head:first-child+body .DHTMLSuite_windowActiveTabCellContent { /* Transparent png for other browsers than IE6 */ + background-image:url('../images/window-theme-windows/tab-active-left.png'); + padding-top:0px; +} + + +.DHTMLSuite_windowInactiveTabCellContent{ + background-image:url('../images/window-theme-windows/tab-inactive-left.gif'); + padding-bottom:1px; +} + +head:first-child+body .DHTMLSuite_windowInactiveTabCellContent { /* Transparent png for other browsers than IE6 */ + background-image:url('../images/window-theme-windows/tab-inactive-left.png'); +} + + +.DHTMLSuite_windowContent{ + overflow:auto; + background-color:#E2E2E2; + margin-left:0px; + margin-right:0px; + border-top:1px solid #FFF; + padding-bottom:1px; + position:relative; + font-size:0.9em; +} + +.DHTMLSuite_windowContent .DHTMLSuite_windowContentInner{ /* Div for each of the tab content divs */ + padding:1px; +} +/* Start css for window status bar */ +.DHTMLSuite_windowStatusBar{ + height:14px; + border-top:1px solid #ACA899; + background-color:#E2E2E2; + position:relative; + overflow:hidden; +} +.DHTMLSuite_windowStatusBarText{ /* Text inside status bar */ + font-size:11px; + line-height:13px; + padding:1px; +} + +.DHTMLSuite_windowResizeHandle{ + background-image:url('../images/window-theme-windows/resize-handle-bottom-right.gif'); + background-repeat:no-repeat; + position:absolute; + bottom:1px; + right:1px; + width:14px; + height:14px; + border-left:1px solid #ACA899; +} diff --git a/ext/dhtml-suite-for-applications/themes/tmw/css/window.css b/ext/dhtml-suite-for-applications/themes/tmw/css/window.css index 65cb1d3..dd6ae27 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/css/window.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/css/window.css @@ -1,214 +1,214 @@ -/************************************************************************************************************ - - DHTML Suite for Applications - (C) www.dhtmlgoodies.com, January 2007 - - CSS for the DHTMLSuite.window class - - - www.dhtmlgoodies.com - Alf Magne Kalleland - - NOTE: You will get nicer images if you change to tab-active-right.gif,tab-active-left.gif, tab-inactive-left.gif and tab-inactive-right.gif to pgn, but gif file has been used because of problems in IE with PNG - -************************************************************************************************************/ - -.DHTMLSuite_window{ /* The bar that is parent of the menu strip */ - background-color:#FFF; - border:1px solid #555555; - width:330px; - height:200px; - overflow:hidden; - top:0px; - left:0px; - z-index:1000; - -} - -.DHTMLSuite_windowInnerDiv{ /* This div is the parent parent element of window elements such as tabs, content and status bar, i.e. the primary main parent element for a window */ - position:relative; - background-color:#FFF; - top:0px; - left:0px; - width:100%; - height:100%; - background-color:#666; -} - -.DHTMLSuite_windowTitleBar{ - background-image:url(../images/window/window_titlebar.png); - background-repeat:repeat-x; - height:17px; - position:relative; /* IMPORTANT */ -} -.DHTMLSuite_windowTitleInTitleBar{ /* The title text in the title bar */ - padding:1px; - font-size:11px; - color:#FFF; -} -.DHTMLSuite_windowButtonDiv{ /* Div for the buttons in the title bar */ - position:absolute; - right:1px; - top:1px; - width:40px; - cursor:default; -} - -.DHTMLSuite_windowButtonDiv div{ - float:right; - position:relative; -} -/* General button rules */ -.DHTMLSuite_windowMinimizeButton,.DHTMLSuite_windowCloseButton,.DHTMLSuite_windowMaximizeButton{ - background-repeat:no-repeat; - background-position:center center; - padding:2px; - width:11px; - height:11px; - -} - -/* Close button */ -.DHTMLSuite_windowCloseButton{ - background-image:url(../images/window/window-close.gif); -} -.DHTMLSuite_windowCloseButtonOver{ - cursor:default; -} - -.DHTMLSuite_windowMinimizeButtonOver,.DHTMLSuite_windowMaximizeButtonOver,.DHTMLSuite_windowCloseButtonOver{ - padding:1px; - background-color:#444; - border:1px solid #666; -} - -/* Minimize button */ -.DHTMLSuite_windowMinimizeButton{ - background-image:url(../images/window/window-minimize.gif); -} -.DHTMLSuite_windowMinimizeButtonOver{ - cursor:default; -} -/* Minimize button */ -.DHTMLSuite_windowMaximizeButton{ - background-image:url(../images/window/window-maximize.gif); -} -DIV.DHTMLSuite_windowMaximizeButton.DHTMLSuite_windowMaximizeButtonOver{ - cursor:default; -} - -/* CSS for the tab row */ -.DHTMLSuite_windowTabRow{ - background-color:#666; - padding-top:1px; - height:26px; - border-top:1px solid #555555; - padding-left:5px; - position:relative; - width:1900px; - z-index:500; /* IMPORTANT */ -} -.DHTMLSuite_windowTabRow table{ - padding-top:3px; -} -.DHTMLSuite_windowTabRow td{ - text-overflow:ellipsis; - white-space:nowrap; - font-weight:bold; -} -.DHTMLSuite_windowTabRow td div{ - -} -.DHTMLSuite_windowATab{ - float:left; - background-position:bottom right; - background-repeat:no-repeat; - height:23px; - cursor:default; - font-size:11px; - line-height:26px; - font-family:arial; - overflow:hidden; -} - -.DHTMLSuite_windowATabInnerDiv{ - background-repeat:no-repeat; - background-position:bottom left; - height:23px; - position:relative; - z-index:10000; - padding-left:5px; - margin-right:25px; - padding-right:4px; -} - -.DHTMLSuite_windowActiveTabCell{ /* Active tab - td tag */ - background-image:url('../images/window/tab-active-right.gif'); - position:relative; - bottom:-1px; -} - -head:first-child+body .DHTMLSuite_windowActiveTabCell { /* Transparent png for other browsers than IE6 */ - background-image:url('../images/window/tab-active-right.png'); -} - -.DHTMLSuite_windowInactiveTabCell{ /* Inactive tab, tag */ - background-image:url('../images/window/tab-inactive-right.gif'); - position:relative; -} - -head:first-child+body .DHTMLSuite_windowInactiveTabCell { /* Transparent png for other browsers than IE6 */ - background-image:url('../images/window/tab-inactive-right.png'); -} - - - -.DHTMLSuite_windowActiveTabCellContent{ /* Active tab - inner div */ - background-image:url('../images/window/tab-active-left.png'); - height:21px; /* These three lines are added in order to make the text of active tab appear on line with text of inactive tabs */ - line-height:24px; - padding-bottom:2px; -} -.DHTMLSuite_windowInactiveTabCellContent{ - background-image:url('../images/window/tab-inactive-left.png'); -} - - -.DHTMLSuite_windowContent{ - overflow:auto; - background-color:#FFF; - margin-left:2px; - margin-right:2px; - border:1px solid #555555; - padding-bottom:1px; - position:relative; -} - -.DHTMLSuite_windowContent .DHTMLSuite_windowContentInner{ /* Div for each of the tab content divs */ - padding:1px; -} -/* Start css for window status bar */ -.DHTMLSuite_windowStatusBar{ - height:14px; - border:1px solid #555555; - background-color:#666; - margin:2px; - position:relative; - overflow:hidden; -} -.DHTMLSuite_windowStatusBarText{ /* Text inside status bar */ - font-size:11px; - line-height:13px; - padding:1px; - color:#FFF; -} - -.DHTMLSuite_windowResizeHandle{ - background-image:url('../images/window/resize-handle-bottom-right.gif'); - background-repeat:no-repeat; - position:absolute; - bottom:1px; - right:1px; - width:14px; - height:14px; -} +/************************************************************************************************************ + + DHTML Suite for Applications + (C) www.dhtmlgoodies.com, January 2007 + + CSS for the DHTMLSuite.window class + + + www.dhtmlgoodies.com + Alf Magne Kalleland + + NOTE: You will get nicer images if you change to tab-active-right.gif,tab-active-left.gif, tab-inactive-left.gif and tab-inactive-right.gif to pgn, but gif file has been used because of problems in IE with PNG + +************************************************************************************************************/ + +.DHTMLSuite_window{ /* The bar that is parent of the menu strip */ + background-color:#FFF; + border:1px solid #555555; + width:330px; + height:200px; + overflow:hidden; + top:0px; + left:0px; + z-index:1000; + +} + +.DHTMLSuite_windowInnerDiv{ /* This div is the parent parent element of window elements such as tabs, content and status bar, i.e. the primary main parent element for a window */ + position:relative; + background-color:#FFF; + top:0px; + left:0px; + width:100%; + height:100%; + background-color:#666; +} + +.DHTMLSuite_windowTitleBar{ + background-image:url(../images/window/window_titlebar.png); + background-repeat:repeat-x; + height:17px; + position:relative; /* IMPORTANT */ +} +.DHTMLSuite_windowTitleInTitleBar{ /* The title text in the title bar */ + padding:1px; + font-size:11px; + color:#FFF; +} +.DHTMLSuite_windowButtonDiv{ /* Div for the buttons in the title bar */ + position:absolute; + right:1px; + top:1px; + width:40px; + cursor:default; +} + +.DHTMLSuite_windowButtonDiv div{ + float:right; + position:relative; +} +/* General button rules */ +.DHTMLSuite_windowMinimizeButton,.DHTMLSuite_windowCloseButton,.DHTMLSuite_windowMaximizeButton{ + background-repeat:no-repeat; + background-position:center center; + padding:2px; + width:11px; + height:11px; + +} + +/* Close button */ +.DHTMLSuite_windowCloseButton{ + background-image:url(../images/window/window-close.gif); +} +.DHTMLSuite_windowCloseButtonOver{ + cursor:default; +} + +.DHTMLSuite_windowMinimizeButtonOver,.DHTMLSuite_windowMaximizeButtonOver,.DHTMLSuite_windowCloseButtonOver{ + padding:1px; + background-color:#444; + border:1px solid #666; +} + +/* Minimize button */ +.DHTMLSuite_windowMinimizeButton{ + background-image:url(../images/window/window-minimize.gif); +} +.DHTMLSuite_windowMinimizeButtonOver{ + cursor:default; +} +/* Minimize button */ +.DHTMLSuite_windowMaximizeButton{ + background-image:url(../images/window/window-maximize.gif); +} +DIV.DHTMLSuite_windowMaximizeButton.DHTMLSuite_windowMaximizeButtonOver{ + cursor:default; +} + +/* CSS for the tab row */ +.DHTMLSuite_windowTabRow{ + background-color:#666; + padding-top:1px; + height:26px; + border-top:1px solid #555555; + padding-left:5px; + position:relative; + width:1900px; + z-index:500; /* IMPORTANT */ +} +.DHTMLSuite_windowTabRow table{ + padding-top:3px; +} +.DHTMLSuite_windowTabRow td{ + text-overflow:ellipsis; + white-space:nowrap; + font-weight:bold; +} +.DHTMLSuite_windowTabRow td div{ + +} +.DHTMLSuite_windowATab{ + float:left; + background-position:bottom right; + background-repeat:no-repeat; + height:23px; + cursor:default; + font-size:11px; + line-height:26px; + font-family:arial; + overflow:hidden; +} + +.DHTMLSuite_windowATabInnerDiv{ + background-repeat:no-repeat; + background-position:bottom left; + height:23px; + position:relative; + z-index:10000; + padding-left:5px; + margin-right:25px; + padding-right:4px; +} + +.DHTMLSuite_windowActiveTabCell{ /* Active tab - td tag */ + background-image:url('../images/window/tab-active-right.gif'); + position:relative; + bottom:-1px; +} + +head:first-child+body .DHTMLSuite_windowActiveTabCell { /* Transparent png for other browsers than IE6 */ + background-image:url('../images/window/tab-active-right.png'); +} + +.DHTMLSuite_windowInactiveTabCell{ /* Inactive tab, tag */ + background-image:url('../images/window/tab-inactive-right.gif'); + position:relative; +} + +head:first-child+body .DHTMLSuite_windowInactiveTabCell { /* Transparent png for other browsers than IE6 */ + background-image:url('../images/window/tab-inactive-right.png'); +} + + + +.DHTMLSuite_windowActiveTabCellContent{ /* Active tab - inner div */ + background-image:url('../images/window/tab-active-left.png'); + height:21px; /* These three lines are added in order to make the text of active tab appear on line with text of inactive tabs */ + line-height:24px; + padding-bottom:2px; +} +.DHTMLSuite_windowInactiveTabCellContent{ + background-image:url('../images/window/tab-inactive-left.png'); +} + + +.DHTMLSuite_windowContent{ + overflow:auto; + background-color:#FFF; + margin-left:2px; + margin-right:2px; + border:1px solid #555555; + padding-bottom:1px; + position:relative; +} + +.DHTMLSuite_windowContent .DHTMLSuite_windowContentInner{ /* Div for each of the tab content divs */ + padding:1px; +} +/* Start css for window status bar */ +.DHTMLSuite_windowStatusBar{ + height:14px; + border:1px solid #555555; + background-color:#666; + margin:2px; + position:relative; + overflow:hidden; +} +.DHTMLSuite_windowStatusBarText{ /* Text inside status bar */ + font-size:11px; + line-height:13px; + padding:1px; + color:#FFF; +} + +.DHTMLSuite_windowResizeHandle{ + background-image:url('../images/window/resize-handle-bottom-right.gif'); + background-repeat:no-repeat; + position:absolute; + bottom:1px; + right:1px; + width:14px; + height:14px; +} diff --git a/ext/dhtml-suite-for-applications/themes/tmw/form-validator.css b/ext/dhtml-suite-for-applications/themes/tmw/form-validator.css index 1215469..4d9b0d7 100755 --- a/ext/dhtml-suite-for-applications/themes/tmw/form-validator.css +++ b/ext/dhtml-suite-for-applications/themes/tmw/form-validator.css @@ -1,15 +1,15 @@ -.DHTMLSuite_validInput{ - border:1px solid green; -} -.DHTMLSuite_invalidInput{ - border:1px solid red; -} - -.DHTMLSuite_validInput,.DHTMLSuite_invalidInput{ - padding:1px; - margin:0px; -} -.DHTMLSuite_validInput select{ - margin:0px; - padding:0px; +.DHTMLSuite_validInput{ + border:1px solid green; +} +.DHTMLSuite_invalidInput{ + border:1px solid red; +} + +.DHTMLSuite_validInput,.DHTMLSuite_invalidInput{ + padding:1px; + margin:0px; +} +.DHTMLSuite_validInput select{ + margin:0px; + padding:0px; } \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/MISSING b/ext/jpgraph-3.0.7/MISSING index c67044d..9a6cb76 100644 --- a/ext/jpgraph-3.0.7/MISSING +++ b/ext/jpgraph-3.0.7/MISSING @@ -1,9 +1,9 @@ -# the following files and directories have been removed from distribution as -# they are not needed by manaweb - -removed ./docportal -removed ./src/Examples -removed ./src/flags.dat -removed ./src/flags_thumb35x35.dat -removed ./src/flags_thumb60x60.dat -removed ./src/flags_thumb100x100.dat +# the following files and directories have been removed from distribution as +# they are not needed by manaweb + +removed ./docportal +removed ./src/Examples +removed ./src/flags.dat +removed ./src/flags_thumb35x35.dat +removed ./src/flags_thumb60x60.dat +removed ./src/flags_thumb100x100.dat diff --git a/ext/jpgraph-3.0.7/QPL.txt b/ext/jpgraph-3.0.7/QPL.txt index 66986cb..d299f89 100644 --- a/ext/jpgraph-3.0.7/QPL.txt +++ b/ext/jpgraph-3.0.7/QPL.txt @@ -1,119 +1,119 @@ -THE Q PUBLIC LICENSE version 1.0 - -Copyright (C) 1999 Trolltech AS, Norway. - Everyone is permitted to copy and - distribute this license document. - -The intent of this license is to establish freedom to share and change -the software regulated by this license under the open source model. - -This license applies to any software containing a notice placed by the -copyright holder saying that it may be distributed under the terms of -the Q Public License version 1.0. Such software is herein referred to -as the Software. This license covers modification and distribution of -the Software, use of third-party application programs based on the -Software, and development of free software which uses the Software. - - -Granted Rights - -1. You are granted the non-exclusive rights set forth in this license - provided you agree to and comply with any and all conditions in - this license. Whole or partial distribution of the Software, or - software items that link with the Software, in any form signifies - acceptance of this license. - - -2. You may copy and distribute the Software in unmodified form - provided that the entire package, including - but not restricted to - - copyright, trademark notices and disclaimers, as released by the - initial developer of the Software, is distributed. - - -3. You may make modifications to the Software and distribute your - modifications, in a form that is separate from the Software, such - as patches. The following restrictions apply to modifications: - - a. Modifications must not alter or remove any copyright notices in the - Software. - - b. When modifications to the Software are released under this license, - a non-exclusive royalty-free right is granted to the initial developer - of the Software to distribute your modification in future versions of - the Software provided such versions remain available under these terms - in addition to any other license(s) of the initial developer. - - -4. You may distribute machine-executable forms of the Software or - machine-executable forms of modified versions of the Software, - provided that you meet these restrictions: - - a. You must include this license document in the distribution. - - b. You must ensure that all recipients of the machine-executable forms - are also able to receive the complete machine-readable source code to - the distributed Software, including all modifications, without any - charge beyond the costs of data transfer, and place prominent notices - in the distribution explaining this. - - c. You must ensure that all modifications included in the - machine-executable forms are available under the terms of this - license. - - -5. You may use the original or modified versions of the Software to - compile, link and run application programs legally developed by you - or by others. - - -6. You may develop application programs, reusable components and other - software items that link with the original or modified versions of - the Software. These items, when distributed, are subject to the - following requirements: - - - - a. You must ensure that all recipients of machine-executable forms of - these items are also able to receive and use the complete - machine-readable source code to the items without any charge beyond - the costs of data transfer. - - - b. You must explicitly license all recipients of your items to use and - re-distribute original and modified versions of the items in both - machine-executable and source code forms. The recipients must be able - to do so without any charges whatsoever, and they must be able to - re-distribute to anyone they choose. - - - c. If the items are not available to the general public, and the - initial developer of the Software requests a copy of the items, then - you must supply one. - - -Limitations of Liability - -In no event shall the initial developers or copyright holders be -liable for any damages whatsoever, including - but not restricted to - -lost revenue or profits or other direct, indirect, special, incidental -or consequential damages, even if they have been advised of the -possibility of such damages, except to the extent invariable law, if -any, provides otherwise. - - -No Warranty - -The Software and this license document are provided AS IS with NO -WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - -Choice of Law - -This license is governed by the Laws of Norway. Disputes shall be -settled by Oslo City Court. - - - - - +THE Q PUBLIC LICENSE version 1.0 + +Copyright (C) 1999 Trolltech AS, Norway. + Everyone is permitted to copy and + distribute this license document. + +The intent of this license is to establish freedom to share and change +the software regulated by this license under the open source model. + +This license applies to any software containing a notice placed by the +copyright holder saying that it may be distributed under the terms of +the Q Public License version 1.0. Such software is herein referred to +as the Software. This license covers modification and distribution of +the Software, use of third-party application programs based on the +Software, and development of free software which uses the Software. + + +Granted Rights + +1. You are granted the non-exclusive rights set forth in this license + provided you agree to and comply with any and all conditions in + this license. Whole or partial distribution of the Software, or + software items that link with the Software, in any form signifies + acceptance of this license. + + +2. You may copy and distribute the Software in unmodified form + provided that the entire package, including - but not restricted to + - copyright, trademark notices and disclaimers, as released by the + initial developer of the Software, is distributed. + + +3. You may make modifications to the Software and distribute your + modifications, in a form that is separate from the Software, such + as patches. The following restrictions apply to modifications: + + a. Modifications must not alter or remove any copyright notices in the + Software. + + b. When modifications to the Software are released under this license, + a non-exclusive royalty-free right is granted to the initial developer + of the Software to distribute your modification in future versions of + the Software provided such versions remain available under these terms + in addition to any other license(s) of the initial developer. + + +4. You may distribute machine-executable forms of the Software or + machine-executable forms of modified versions of the Software, + provided that you meet these restrictions: + + a. You must include this license document in the distribution. + + b. You must ensure that all recipients of the machine-executable forms + are also able to receive the complete machine-readable source code to + the distributed Software, including all modifications, without any + charge beyond the costs of data transfer, and place prominent notices + in the distribution explaining this. + + c. You must ensure that all modifications included in the + machine-executable forms are available under the terms of this + license. + + +5. You may use the original or modified versions of the Software to + compile, link and run application programs legally developed by you + or by others. + + +6. You may develop application programs, reusable components and other + software items that link with the original or modified versions of + the Software. These items, when distributed, are subject to the + following requirements: + + + + a. You must ensure that all recipients of machine-executable forms of + these items are also able to receive and use the complete + machine-readable source code to the items without any charge beyond + the costs of data transfer. + + + b. You must explicitly license all recipients of your items to use and + re-distribute original and modified versions of the items in both + machine-executable and source code forms. The recipients must be able + to do so without any charges whatsoever, and they must be able to + re-distribute to anyone they choose. + + + c. If the items are not available to the general public, and the + initial developer of the Software requests a copy of the items, then + you must supply one. + + +Limitations of Liability + +In no event shall the initial developers or copyright holders be +liable for any damages whatsoever, including - but not restricted to - +lost revenue or profits or other direct, indirect, special, incidental +or consequential damages, even if they have been advised of the +possibility of such damages, except to the extent invariable law, if +any, provides otherwise. + + +No Warranty + +The Software and this license document are provided AS IS with NO +WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +Choice of Law + +This license is governed by the Laws of Norway. Disputes shall be +settled by Oslo City Court. + + + + + diff --git a/ext/jpgraph-3.0.7/README b/ext/jpgraph-3.0.7/README index 963cc5c..206a073 100644 --- a/ext/jpgraph-3.0.7/README +++ b/ext/jpgraph-3.0.7/README @@ -1,71 +1,71 @@ -README FOR JPGRAPH 3.0.x -======================== - -This package contains JpGraph, an Object Oriented PHP5 Graph Plotting library. - -The library is Copyright (C) 2001-2009 Aditus Consulting and -released under dual license QPL 1.0 for open source and educational -use and JpGraph Professional License for commercial use. - -Please see full license details at http://www.aditus.nu/jpgraph/ - -* -------------------------------------------------------------------- -* PHP4 IS NOT SUPPORTED in the 2.x or 3.x series -* -------------------------------------------------------------------- - -Requirements: -------------- -Miminum: -* PHP 5.1.0 or higher -* GD 2.0.28 or higher -Note: Earlier versions might work but is unsupported. - -Recommended: -* PHP >= 5.2.0 -* PHP Built-in GD library - -Installation ------------- -0. Make sure that the PHP version is compatible with the stated requirements - and that the PHP installation has support for the GD library. - Please run phpinfo() to check if GD library - is supported in the installation. - If the GD library doesn't seem to be installed - please consult the PHP manual under section "Image" for - instructions on where to find this library. Please refer to - the manual section "Verifying your PHP installation" - -1. Unzip and copy the files to a directory of your choice where Your - httpd sever can access them. - For a global site installation you should copy the files to - somewhere in the PHP search path. - -2. Check that the default directory paths in jpg-config.inc - for cache directory and TTF directory suits your installation. - Note1: The default directories are different depending on if - the library is running on Windows or UNIX. - Note2: Apache/PHP must have write permission to your cache - directory if you enable the cache feature. By default the cache - is disabled. - -3. Check that all rest of the DEFINE in jpg-config.inc - is setup to your preference. The default should be fine - for most users. - -4. Read the chapters on installation in the manual. - - -Documentation -------------- -The installation includes HTML documentation and reference guide for the -library. The portal page for all the documentation is -/docs/index.html - - -Bug reports and suggestions ---------------------------- -Should be reported using the the issue tracker at - -http://www.aditus.nu/bugtraq - - +README FOR JPGRAPH 3.0.x +======================== + +This package contains JpGraph, an Object Oriented PHP5 Graph Plotting library. + +The library is Copyright (C) 2001-2009 Aditus Consulting and +released under dual license QPL 1.0 for open source and educational +use and JpGraph Professional License for commercial use. + +Please see full license details at http://www.aditus.nu/jpgraph/ + +* -------------------------------------------------------------------- +* PHP4 IS NOT SUPPORTED in the 2.x or 3.x series +* -------------------------------------------------------------------- + +Requirements: +------------- +Miminum: +* PHP 5.1.0 or higher +* GD 2.0.28 or higher +Note: Earlier versions might work but is unsupported. + +Recommended: +* PHP >= 5.2.0 +* PHP Built-in GD library + +Installation +------------ +0. Make sure that the PHP version is compatible with the stated requirements + and that the PHP installation has support for the GD library. + Please run phpinfo() to check if GD library + is supported in the installation. + If the GD library doesn't seem to be installed + please consult the PHP manual under section "Image" for + instructions on where to find this library. Please refer to + the manual section "Verifying your PHP installation" + +1. Unzip and copy the files to a directory of your choice where Your + httpd sever can access them. + For a global site installation you should copy the files to + somewhere in the PHP search path. + +2. Check that the default directory paths in jpg-config.inc + for cache directory and TTF directory suits your installation. + Note1: The default directories are different depending on if + the library is running on Windows or UNIX. + Note2: Apache/PHP must have write permission to your cache + directory if you enable the cache feature. By default the cache + is disabled. + +3. Check that all rest of the DEFINE in jpg-config.inc + is setup to your preference. The default should be fine + for most users. + +4. Read the chapters on installation in the manual. + + +Documentation +------------- +The installation includes HTML documentation and reference guide for the +library. The portal page for all the documentation is +/docs/index.html + + +Bug reports and suggestions +--------------------------- +Should be reported using the the issue tracker at + +http://www.aditus.nu/bugtraq + + diff --git a/ext/jpgraph-3.0.7/VERSION b/ext/jpgraph-3.0.7/VERSION index 92f61ae..3b52e9f 100644 --- a/ext/jpgraph-3.0.7/VERSION +++ b/ext/jpgraph-3.0.7/VERSION @@ -1 +1 @@ -Version: v3.0.7, Build: r1928, Exported: Mon, 11 Jan 2010 at 23:34 (UTC+2), w1002.1 +Version: v3.0.7, Build: r1928, Exported: Mon, 11 Jan 2010 at 23:34 (UTC+2), w1002.1 diff --git a/ext/jpgraph-3.0.7/src/contour_dev/findpolygon.php b/ext/jpgraph-3.0.7/src/contour_dev/findpolygon.php index a8df761..7622fc9 100644 --- a/ext/jpgraph-3.0.7/src/contour_dev/findpolygon.php +++ b/ext/jpgraph-3.0.7/src/contour_dev/findpolygon.php @@ -1,798 +1,798 @@ -contourCoord[0]); ++$i) { - // echo '('.$this->contourCoord[0][$i][0][0].','.$this->contourCoord[0][$i][0][1].') -> '. - // '('.$this->contourCoord[0][$i][1][0].','.$this->contourCoord[0][$i][1][1].")\n"; - // } - // - - $c=0; - $p[$c] = array(0.6,1, 1,0.5, 2,0.5, 3,0.5, 3.5,1, 3.5,2, 3,2.5, 2,2.5, 1,2.5, 0.5,2, 0.6,1); - $c++; - $p[$c] = array(6,0.5, 5.5,1, 5.5,2, 6,2.5); - - $this->nbrContours = $c+1; - - for ($c = 0 ; $c < count($p) ; $c++) { - $n=count($p[$c]); - - $this->contourCoord[$c][0] = array(array($p[$c][0],$p[$c][1]),array($p[$c][2],$p[$c][3])); - $k=1; - for ($i = 0; $i < ($n-4)/2; $i++, $k++) { - $this->contourCoord[$c][$k] = array($this->contourCoord[$c][$k-1][1], array($p[$c][2*$k+2],$p[$c][2*$k+1+2])); - } - - // Swap edges order at random - $n = count($this->contourCoord[$c]); - for($i=0; $i < floor($n/2); ++$i) { - $swap1 = rand(0,$n-1); - $t = $this->contourCoord[$c][$swap1]; - while( $swap1 == ($swap2 = rand(0,$n-1)) ) - ; - $this->contourCoord[$c][$swap1] = $this->contourCoord[$c][$swap2]; - $this->contourCoord[$c][$swap2] = $t; - } - - // Swap vector direction on 1/3 of the edges - for ($i = 0 ; $i < floor(count($this->contourCoord[$c])/3) ; $i++) { - $e = rand(0, count($this->contourCoord[$c])-1); - $edge = $this->contourCoord[$c][$e]; - $v1 = $edge[0]; $v2 = $edge[1]; - $this->contourCoord[$c][$e][0] = $v2; - $this->contourCoord[$c][$e][1] = $v1; - } - } - - $pp = array(); - for($j=0; $j < count($p); ++$j ) { - for( $i=0; $i < count($p[$j])/2; ++$i ) { - $pp[$j][$i] = array($p[$j][2*$i],$p[$j][2*$i+1]); - } - } - return $pp; - } - - function p_edges($v) { - for ($i = 0 ; $i < count($v) ; $i++) { - echo "(".$v[$i][0][0].",".$v[$i][0][1].") -> (".$v[$i][1][0].",".$v[$i][1][1].")\n"; - } - echo "\n"; - } - - function CompareCyclic($a,$b,$forward=true) { - - // We assume disjoint vertices and if last==first this just means - // that the polygon is closed. For this comparison it must be unique - // elements - if( $a[count($a)-1] == $a[0] ) { - array_pop($a); - } - if( $b[count($b)-1] == $b[0] ) { - array_pop($b); - } - - $n1 = count($a); $n2 = count($b); - if( $n1 != $n2 ) - return false; - - $i=0; - while( ($i < $n2) && ($a[0] != $b[$i]) ) - ++$i; - - if( $i >= $n2 ) - return false; - - $j=0; - if( $forward ) { - while( ($j < $n1) && ($a[$j] == $b[$i]) ) { - $i = ($i + 1) % $n2; - ++$j; - } - } - else { - while( ($j < $n1) && ($a[$j] == $b[$i]) ) { - --$i; - if( $i < 0 ) { - $i = $n2-1; - } - ++$j; - } - } - return $j >= $n1; - } - - function dbg($s) { - // echo $s."\n"; - } - - function IsVerticeOnBorder($x1,$y1) { - // Check if the vertice lies on any of the four border - if( $x1==$this->scale[0] || $x1==$this->scale[1] ) { - return true; - } - if( $y1==$this->scale[2] || $y1==$this->scale[3] ) { - return true; - } - return false; - } - - function FindPolygons($debug=false) { - - $pol = 0; - for ($c = 0; $c < $this->nbrContours; $c++) { - - $this->dbg("\n** Searching polygon chain $c ... "); - $this->dbg("------------------------------------------\n"); - - $edges = $this->contourCoord[$c]; - while( count($edges) > 0 ) { - - $edge = array_shift($edges); - list($x1,$y1) = $edge[0]; - list($x2,$y2) = $edge[1]; - $polygons[$pol]=array( - array($x1,$y1),array($x2,$y2) - ); - - $this->dbg("Searching on second vertice."); - - $found=false; - if( ! $this->IsVerticeOnBorder($x2,$y2) ) { - do { - - $this->dbg(" --Searching on edge: ($x1,$y1)->($x2,$y2)"); - - $found=false; - $nn = count($edges); - for( $i=0; $i < $nn && !$found; ++$i ) { - $edge = $edges[$i]; - if( $found = ($x2==$edge[0][0] && $y2==$edge[0][1]) ) { - $polygons[$pol][] = array($edge[1][0],$edge[1][1]); - $x1 = $x2; $y1 = $y2; - $x2 = $edge[1][0]; $y2 = $edge[1][1]; - } - elseif( $found = ($x2==$edge[1][0] && $y2==$edge[1][1]) ) { - $polygons[$pol][] = array($edge[0][0],$edge[0][1]); - $x1 = $x2; $y1 = $y2; - $x2 = $edge[0][0]; $y2 = $edge[0][1]; - } - if( $found ) { - $this->dbg(" --Found next edge: [i=$i], (%,%) -> ($x2,$y2)"); - unset($edges[$i]); - $edges = array_values($edges); - } - } - - } while( $found ); - } - - if( !$found && count($edges)>0 ) { - $this->dbg("Searching on first vertice."); - list($x1,$y1) = $polygons[$pol][0]; - list($x2,$y2) = $polygons[$pol][1]; - - if( ! $this->IsVerticeOnBorder($x1,$y1) ) { - do { - - $this->dbg(" --Searching on edge: ($x1,$y1)->($x2,$y2)"); - - $found=false; - $nn = count($edges); - for( $i=0; $i < $nn && !$found; ++$i ) { - $edge = $edges[$i]; - if( $found = ($x1==$edge[0][0] && $y1==$edge[0][1]) ) { - array_unshift($polygons[$pol],array($edge[1][0],$edge[1][1])); - $x2 = $x1; $y2 = $y1; - $x1 = $edge[1][0]; $y1 = $edge[1][1]; - } - elseif( $found = ($x1==$edge[1][0] && $y1==$edge[1][1]) ) { - array_unshift($polygons[$pol],array($edge[0][0],$edge[0][1])); - $x2 = $x1; $y2 = $y1; - $x1 = $edge[0][0]; $y1 = $edge[0][1]; - } - if( $found ) { - $this->dbg(" --Found next edge: [i=$i], ($x1,$y1) -> (%,%)"); - unset($edges[$i]); - $edges = array_values($edges); - } - } - - } while( $found ); - } - - } - - $pol++; - } - } - - return $polygons; - } - -} -define('HORIZ_EDGE',0); -define('VERT_EDGE',1); - -class FillGridRect { - private $edges,$dataPoints,$colors,$isoBars; - private $invert=false; - - function __construct(&$edges,&$dataPoints,$isoBars,$colors) { - $this->edges = $edges; - $this->dataPoints = $dataPoints; - $this->colors = $colors; - $this->isoBars = $isoBars; - } - - function GetIsobarColor($val) { - for ($i = 0 ; $i < count($this->isoBars) ; $i++) { - if( $val <= $this->isoBars[$i] ) { - return $this->colors[$i]; - } - } - return $this->colors[$i]; // The color for all values above the highest isobar - } - - function GetIsobarVal($a,$b) { - // Get the isobar that is between the values a and b - // If there are more isobars then return the one with lowest index - if( $b < $a ) { - $t=$a; $a=$b; $b=$t; - } - $i = 0 ; - $n = count($this->isoBars); - while( $i < $n && $this->isoBars[$i] < $a ) { - ++$i; - } - if( $i >= $n ) - die("Internal error. Cannot find isobar values for ($a,$b)"); - return $this->isoBars[$i]; - } - - function getCrossingCoord($aRow,$aCol,$aEdgeDir,$aIsobarVal) { - // In order to avoid numerical problem when two vertices are very close - // we have to check and avoid dividing by close to zero denumerator. - if( $aEdgeDir == HORIZ_EDGE ) { - $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow][$aCol+1]); - if( $d > 0.001 ) { - $xcoord = $aCol + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; - } - else { - $xcoord = $aCol; - } - $ycoord = $aRow; - } - else { - $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow+1][$aCol]); - if( $d > 0.001 ) { - $ycoord = $aRow + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; - } - else { - $ycoord = $aRow; - } - $xcoord = $aCol; - } - if( $this->invert ) { - $ycoord = $this->nbrRows-1 - $ycoord; - } - return array($xcoord,$ycoord); - } - - function Fill(ContCanvas $canvas) { - - $nx_vertices = count($this->dataPoints[0]); - $ny_vertices = count($this->dataPoints); - - // Loop through all squares in the grid - for($col=0; $col < $nx_vertices-1; ++$col) { - for($row=0; $row < $ny_vertices-1; ++$row) { - - $n = 0;$quad_edges=array(); - if ( $this->edges[VERT_EDGE][$row][$col] ) $quad_edges[$n++] = array($row, $col, VERT_EDGE); - if ( $this->edges[VERT_EDGE][$row][$col+1] ) $quad_edges[$n++] = array($row, $col+1,VERT_EDGE); - if ( $this->edges[HORIZ_EDGE][$row][$col] ) $quad_edges[$n++] = array($row, $col, HORIZ_EDGE); - if ( $this->edges[HORIZ_EDGE][$row+1][$col] ) $quad_edges[$n++] = array($row+1,$col, HORIZ_EDGE); - - if( $n == 0 ) { - // Easy, fill the entire quadrant with one color since we have no crossings - // Select the top left datapoint as representing this quadrant - // color for this quadrant - $color = $this->GetIsobarColor($this->dataPoints[$row][$col]); - $polygon = array($col,$row,$col,$row+1,$col+1,$row+1,$col+1,$row,$col,$row); - $canvas->FilledPolygon($polygon,$color); - - } elseif( $n==2 ) { - - // There is one isobar edge crossing this quadrant. In order to fill we need to - // find out the orientation of the two areas this edge is separating in order to - // construct the two polygons that define the two areas to be filled - // There are six possible variants - // 0) North-South - // 1) West-East - // 2) West-North - // 3) East-North - // 4) West-South - // 5) East-South - $type=-1; - if( $this->edges[HORIZ_EDGE][$row][$col] ) { - if( $this->edges[HORIZ_EDGE][$row+1][$col] ) $type=0; // North-South - elseif( $this->edges[VERT_EDGE][$row][$col] ) $type=2; - elseif( $this->edges[VERT_EDGE][$row][$col+1] ) $type=3; - } - elseif( $this->edges[HORIZ_EDGE][$row+1][$col] ) { - if( $this->edges[VERT_EDGE][$row][$col] ) $type=4; - elseif( $this->edges[VERT_EDGE][$row][$col+1] ) $type=5; - } - else { - $type=1; - } - if( $type==-1 ) { - die('Internal error: n=2 but no edges in the quadrant was find to determine type.'); - } - - switch( $type ) { - case 0: //North-South - - // North vertice - $v1 = $this->dataPoints[$row][$col]; - $v2 = $this->dataPoints[$row][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x1,$y1) = $this->getCrossingCoord($row, $col,HORIZ_EDGE, $isobarValue); - - // South vertice - $v1 = $this->dataPoints[$row+1][$col]; - $v2 = $this->dataPoints[$row+1][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x2,$y2) = $this->getCrossingCoord($row+1, $col,HORIZ_EDGE, $isobarValue); - - $polygon = array($col,$row,$x1,$y1,$x2,$y2,$col,$row+1,$col,$row); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); - - $polygon = array($col+1,$row,$x1,$y1,$x2,$y2,$col+1,$row+1,$col+1,$row); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); - - break; - - case 1: // West-East - - // West vertice - $v1 = $this->dataPoints[$row][$col]; - $v2 = $this->dataPoints[$row+1][$col]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x1,$y1) = $this->getCrossingCoord($row, $col,VERT_EDGE, $isobarValue); - - // East vertice - $v1 = $this->dataPoints[$row][$col+1]; - $v2 = $this->dataPoints[$row+1][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x2,$y2) = $this->getCrossingCoord($row, $col+1,VERT_EDGE, $isobarValue); - - $polygon = array($col,$row,$x1,$y1,$x2,$y2,$col+1,$row,$col,$row); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); - - $polygon = array($col,$row+1,$x1,$y1,$x2,$y2,$col+1,$row+1,$col,$row+1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); - break; - - case 2: // West-North - - // West vertice - $v1 = $this->dataPoints[$row][$col]; - $v2 = $this->dataPoints[$row+1][$col]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x1,$y1) = $this->getCrossingCoord($row, $col,VERT_EDGE, $isobarValue); - - // North vertice - $v1 = $this->dataPoints[$row][$col]; - $v2 = $this->dataPoints[$row][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x2,$y2) = $this->getCrossingCoord($row, $col,HORIZ_EDGE, $isobarValue); - - $polygon = array($col,$row,$x1,$y1,$x2,$y2,$col,$row); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); - - $polygon = array($x1,$y1,$x2,$y2,$col+1,$row,$col+1,$row+1,$col,$row+1,$x1,$y1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); - - break; - - case 3: // East-North - - // if( $row==3 && $col==1 && $n==2 ) { - // echo " ** East-North
      "; - // } - - - // East vertice - $v1 = $this->dataPoints[$row][$col+1]; - $v2 = $this->dataPoints[$row+1][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x1,$y1) = $this->getCrossingCoord($row, $col+1,VERT_EDGE, $isobarValue); - // - // if( $row==3 && $col==1 && $n==2 ) { - // echo " ** E_val($v1,$v2), isobar=$isobarValue
      "; - // echo " ** E($x1,$y1)
      "; - // } - - - // North vertice - $v1 = $this->dataPoints[$row][$col]; - $v2 = $this->dataPoints[$row][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x2,$y2) = $this->getCrossingCoord($row, $col,HORIZ_EDGE, $isobarValue); - - // if( $row==3 && $col==1 && $n==2 ) { - // echo " ** N_val($v1,$v2), isobar=$isobarValue
      "; - // echo " ** N($x2,$y2)
      "; - // } - // if( $row==3 && $col==1 && $n==2 ) - // $canvas->Line($x1,$y1,$x2,$y2,'blue'); - - $polygon = array($x1,$y1,$x2,$y2,$col+1,$row,$x1,$y1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); - - $polygon = array($col,$row,$x2,$y2,$x1,$y1,$col+1,$row+1,$col,$row+1,$col,$row); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); - - break; - - case 4: // West-South - - // West vertice - $v1 = $this->dataPoints[$row][$col]; - $v2 = $this->dataPoints[$row+1][$col]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x1,$y1) = $this->getCrossingCoord($row, $col,VERT_EDGE, $isobarValue); - - // South vertice - $v1 = $this->dataPoints[$row+1][$col]; - $v2 = $this->dataPoints[$row+1][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x2,$y2) = $this->getCrossingCoord($row+1, $col,HORIZ_EDGE, $isobarValue); - - $polygon = array($col,$row+1,$x1,$y1,$x2,$y2,$col,$row+1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); - - $polygon = array($x1,$y1,$x2,$y2,$col+1,$row+1,$col+1,$row,$col,$row,$x1,$y1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); - - break; - - case 5: // East-South - - // - // if( $row==1 && $col==1 && $n==2 ) { - // echo " ** Sout-East
      "; - // } - - // East vertice - $v1 = $this->dataPoints[$row][$col+1]; - $v2 = $this->dataPoints[$row+1][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x1,$y1) = $this->getCrossingCoord($row, $col+1,VERT_EDGE, $isobarValue); - - // if( $row==1 && $col==1 && $n==2 ) { - // echo " ** E_val($v1,$v2), isobar=$isobarValue
      "; - // echo " ** E($x1,$y1)
      "; - // } - - // South vertice - $v1 = $this->dataPoints[$row+1][$col]; - $v2 = $this->dataPoints[$row+1][$col+1]; - $isobarValue = $this->GetIsobarVal($v1, $v2); - list($x2,$y2) = $this->getCrossingCoord($row+1, $col,HORIZ_EDGE, $isobarValue); - - // if( $row==1 && $col==1 && $n==2 ) { - // echo " ** S_val($v1,$v2), isobar=$isobarValue
      "; - // echo " ** S($x2,$y2)
      "; - // } - - $polygon = array($col+1,$row+1,$x1,$y1,$x2,$y2,$col+1,$row+1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); - - $polygon = array($x1,$y1,$x2,$y2,$col,$row+1,$col,$row,$col+1,$row,$x1,$y1); - $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); - - break; - - } - - } - - } - } - - } -} - - -class ContCanvas { - public $g; - public $shape,$scale; - function __construct($xmax=6,$ymax=6,$width=400,$height=400) { - - $this->g = new CanvasGraph($width,$height); - $this->scale = new CanvasScale($this->g, 0, $xmax, 0, $ymax); - $this->shape = new Shape($this->g, $this->scale); - - //$this->g->SetFrame(true); - $this->g->SetMargin(5,5,5,5); - $this->g->SetMarginColor('white@1'); - $this->g->InitFrame(); - - - $this->shape->SetColor('gray'); - for( $col=1; $col<$xmax; ++$col ) { - $this->shape->Line($col, 0, $col, $ymax); - } - for( $row=1; $row<$ymax; ++$row ) { - $this->shape->Line(0, $row, $xmax, $row); - } - } - - function SetDatapoints($datapoints) { - $ny=count($datapoints); - $nx=count($datapoints[0]); - $t = new Text(); - $t->SetFont(FF_ARIAL,FS_NORMAL,8); - for( $x=0; $x < $nx; ++$x ) { - for( $y=0; $y < $ny; ++$y ) { - list($x1,$y1) = $this->scale->Translate($x,$y); - - if( $datapoints[$y][$x] > 0 ) - $t->SetColor('blue'); - else - $t->SetColor('black'); - $t->SetFont(FF_ARIAL,FS_BOLD,8); - $t->Set($datapoints[$y][$x]); - $t->Stroke($this->g->img,$x1,$y1); - - $t->SetColor('gray'); - $t->SetFont(FF_ARIAL,FS_NORMAL,8); - $t->Set("($y,$x)"); - $t->Stroke($this->g->img,$x1+10,$y1); - - } - } - } - - function DrawLinePolygons($p,$color='red') { - $this->shape->SetColor($color); - for ($i = 0 ; $i < count($p) ; $i++) { - $x1 = $p[$i][0][0]; $y1 = $p[$i][0][1]; - for ($j = 1 ; $j < count($p[$i]) ; $j++) { - $x2=$p[$i][$j][0]; $y2 = $p[$i][$j][1]; - $this->shape->Line($x1, $y1, $x2, $y2); - $x1=$x2; $y1=$y2; - } - } - } - - function Line($x1,$y1,$x2,$y2,$color='red') { - $this->shape->SetColor($color); - $this->shape->Line($x1, $y1, $x2, $y2); - } - function Polygon($p,$color='blue') { - $this->shape->SetColor($color); - $this->shape->Polygon($p); - } - - function FilledPolygon($p,$color='lightblue') { - $this->shape->SetColor($color); - $this->shape->FilledPolygon($p); - } - - function Point($x,$y,$color) { - list($x1,$y1) = $this->scale->Translate($x, $y); - $this->shape->SetColor($color); - $this->g->img->Point($x1,$y1); - } - - function Stroke() { - $this->g->Stroke(); - } - -} - - -class PixelFill { - - private $edges,$dataPoints,$colors,$isoBars; - - function __construct(&$edges,&$dataPoints,$isoBars,$colors) { - $this->edges = $edges; - $this->dataPoints = $dataPoints; - $this->colors = $colors; - $this->isoBars = $isoBars; - } - - function GetIsobarColor($val) { - for ($i = 0 ; $i < count($this->isoBars) ; $i++) { - if( $val <= $this->isoBars[$i] ) { - return $this->colors[$i]; - } - } - return $this->colors[$i]; // The color for all values above the highest isobar - } - - function Fill(ContCanvas $canvas) { - - $nx_vertices = count($this->dataPoints[0]); - $ny_vertices = count($this->dataPoints); - - // Loop through all squares in the grid - for($col=0; $col < $nx_vertices-1; ++$col) { - for($row=0; $row < $ny_vertices-1; ++$row) { - - $v=array( - $this->dataPoints[$row][$col], - $this->dataPoints[$row][$col+1], - $this->dataPoints[$row+1][$col+1], - $this->dataPoints[$row+1][$col], - ); - - list($x1,$y1) = $canvas->scale->Translate($col, $row); - list($x2,$y2) = $canvas->scale->Translate($col+1, $row+1); - - for( $x=$x1; $x < $x2; ++$x ) { - for( $y=$y1; $y < $y2; ++$y ) { - - $v1 = $v[0] + ($v[1]-$v[0])*($x-$x1)/($x2-$x1); - $v2 = $v[3] + ($v[2]-$v[3])*($x-$x1)/($x2-$x1); - $val = $v1 + ($v2-$v1)*($y-$y1)/($y2-$y1); - - if( $row==2 && $col==2 ) { - //echo " ($val ($x,$y)) (".$v[0].",".$v[1].",".$v[2].",".$v[3].")
      "; - } - $color = $this->GetIsobarColor($val); - $canvas->g->img->SetColor($color); - $canvas->g->img->Point($x, $y); - } - } - } - } - - } - -} - -$edges=array(array(),array(),array()); -$datapoints=array(); -for($col=0; $col<6; $col++) { - for($row=0; $row<6; $row++) { - $datapoints[$row][$col]=0; - $edges[VERT_EDGE][$row][$col] = false; - $edges[HORIZ_EDGE][$row][$col] = false; - } -} - -$datapoints[1][2] = 2; -$datapoints[2][1] = 1; -$datapoints[2][2] = 7; -$datapoints[2][3] = 2; -$datapoints[3][1] = 2; -$datapoints[3][2] = 17; -$datapoints[3][3] = 4; -$datapoints[4][2] = 3; - -$datapoints[1][4] = 12; - -$edges[VERT_EDGE][1][2] = true; -$edges[VERT_EDGE][3][2] = true; - -$edges[HORIZ_EDGE][2][1] = true; -$edges[HORIZ_EDGE][2][2] = true; -$edges[HORIZ_EDGE][3][1] = true; -$edges[HORIZ_EDGE][3][2] = true; - - - -$isobars = array(5,10,15); -$colors = array('lightgray','lightblue','lightred','red'); - -$engine = new PixelFill($edges, $datapoints, $isobars, $colors); -$canvas = new ContCanvas(); -$engine->Fill($canvas); -$canvas->SetDatapoints($datapoints); -$canvas->Stroke(); -die(); - - -//$tst = new Findpolygon(); -//$p1 = $tst->SetupTestData(); -// -//$canvas = new ContCanvas(); -//for ($i = 0 ; $i < count($tst->contourCoord); $i++) { -// $canvas->DrawLinePolygons($tst->contourCoord[$i]); -//} -// -//$p2 = $tst->FindPolygons(); -//for ($i = 0 ; $i < count($p2) ; $i++) { -// $canvas->FilledPolygon($tst->flattenEdges($p2[$i])); -//} -// -//for ($i = 0 ; $i < count($p2) ; $i++) { -// $canvas->Polygon($tst->flattenEdges($p2[$i])); -//} -// -//$canvas->Stroke(); -//die(); - - -//for( $trial = 0; $trial < 1; ++$trial ) { -// echo "\nTest $trial:\n"; -// echo "========================================\n"; -// $tst = new Findpolygon(); -// $p1 = $tst->SetupTestData(); -// -// // for ($i = 0 ; $i < count($p1) ; $i++) { -// // echo "Test polygon $i:\n"; -// // echo "---------------------\n"; -// // $tst->p_edges($tst->contourCoord[$i]); -// // echo "\n"; -// // } -// // -// $p2 = $tst->FindPolygons(); -// $npol = count($p2); -// //echo "\n** Found $npol separate polygon chains.\n\n"; -// -// for( $i=0; $i<$npol; ++$i ) { -// -// $res_forward = $tst->CompareCyclic($p1[$i], $p2[$i],true); -// $res_backward = $tst->CompareCyclic($p1[$i], $p2[$i],false); -// if( $res_backward || $res_forward ) { -// // if( $res_forward ) -// // echo "Forward matches!\n"; -// // else -// // echo "Backward matches!\n"; -// } -// else { -// echo "********** NO MATCH!!.\n\n"; -// echo "\nBefore find:\n"; -// for ($j = 0 ; $j < count($p1[$i]) ; $j++) { -// echo "(".$p1[$i][$j][0].','.$p1[$i][$j][1]."), "; -// } -// echo "\n"; -// -// echo "\nAfter find:\n"; -// for ($j = 0 ; $j < count($p2[$i]) ; $j++) { -// echo "(".$p2[$i][$j][0].','.$p2[$i][$j][1]."), "; -// } -// echo "\n"; -// } -// -// } -//} -// -//echo "\n\nAll tests ready.\n\n"; -// - - -?> +contourCoord[0]); ++$i) { + // echo '('.$this->contourCoord[0][$i][0][0].','.$this->contourCoord[0][$i][0][1].') -> '. + // '('.$this->contourCoord[0][$i][1][0].','.$this->contourCoord[0][$i][1][1].")\n"; + // } + // + + $c=0; + $p[$c] = array(0.6,1, 1,0.5, 2,0.5, 3,0.5, 3.5,1, 3.5,2, 3,2.5, 2,2.5, 1,2.5, 0.5,2, 0.6,1); + $c++; + $p[$c] = array(6,0.5, 5.5,1, 5.5,2, 6,2.5); + + $this->nbrContours = $c+1; + + for ($c = 0 ; $c < count($p) ; $c++) { + $n=count($p[$c]); + + $this->contourCoord[$c][0] = array(array($p[$c][0],$p[$c][1]),array($p[$c][2],$p[$c][3])); + $k=1; + for ($i = 0; $i < ($n-4)/2; $i++, $k++) { + $this->contourCoord[$c][$k] = array($this->contourCoord[$c][$k-1][1], array($p[$c][2*$k+2],$p[$c][2*$k+1+2])); + } + + // Swap edges order at random + $n = count($this->contourCoord[$c]); + for($i=0; $i < floor($n/2); ++$i) { + $swap1 = rand(0,$n-1); + $t = $this->contourCoord[$c][$swap1]; + while( $swap1 == ($swap2 = rand(0,$n-1)) ) + ; + $this->contourCoord[$c][$swap1] = $this->contourCoord[$c][$swap2]; + $this->contourCoord[$c][$swap2] = $t; + } + + // Swap vector direction on 1/3 of the edges + for ($i = 0 ; $i < floor(count($this->contourCoord[$c])/3) ; $i++) { + $e = rand(0, count($this->contourCoord[$c])-1); + $edge = $this->contourCoord[$c][$e]; + $v1 = $edge[0]; $v2 = $edge[1]; + $this->contourCoord[$c][$e][0] = $v2; + $this->contourCoord[$c][$e][1] = $v1; + } + } + + $pp = array(); + for($j=0; $j < count($p); ++$j ) { + for( $i=0; $i < count($p[$j])/2; ++$i ) { + $pp[$j][$i] = array($p[$j][2*$i],$p[$j][2*$i+1]); + } + } + return $pp; + } + + function p_edges($v) { + for ($i = 0 ; $i < count($v) ; $i++) { + echo "(".$v[$i][0][0].",".$v[$i][0][1].") -> (".$v[$i][1][0].",".$v[$i][1][1].")\n"; + } + echo "\n"; + } + + function CompareCyclic($a,$b,$forward=true) { + + // We assume disjoint vertices and if last==first this just means + // that the polygon is closed. For this comparison it must be unique + // elements + if( $a[count($a)-1] == $a[0] ) { + array_pop($a); + } + if( $b[count($b)-1] == $b[0] ) { + array_pop($b); + } + + $n1 = count($a); $n2 = count($b); + if( $n1 != $n2 ) + return false; + + $i=0; + while( ($i < $n2) && ($a[0] != $b[$i]) ) + ++$i; + + if( $i >= $n2 ) + return false; + + $j=0; + if( $forward ) { + while( ($j < $n1) && ($a[$j] == $b[$i]) ) { + $i = ($i + 1) % $n2; + ++$j; + } + } + else { + while( ($j < $n1) && ($a[$j] == $b[$i]) ) { + --$i; + if( $i < 0 ) { + $i = $n2-1; + } + ++$j; + } + } + return $j >= $n1; + } + + function dbg($s) { + // echo $s."\n"; + } + + function IsVerticeOnBorder($x1,$y1) { + // Check if the vertice lies on any of the four border + if( $x1==$this->scale[0] || $x1==$this->scale[1] ) { + return true; + } + if( $y1==$this->scale[2] || $y1==$this->scale[3] ) { + return true; + } + return false; + } + + function FindPolygons($debug=false) { + + $pol = 0; + for ($c = 0; $c < $this->nbrContours; $c++) { + + $this->dbg("\n** Searching polygon chain $c ... "); + $this->dbg("------------------------------------------\n"); + + $edges = $this->contourCoord[$c]; + while( count($edges) > 0 ) { + + $edge = array_shift($edges); + list($x1,$y1) = $edge[0]; + list($x2,$y2) = $edge[1]; + $polygons[$pol]=array( + array($x1,$y1),array($x2,$y2) + ); + + $this->dbg("Searching on second vertice."); + + $found=false; + if( ! $this->IsVerticeOnBorder($x2,$y2) ) { + do { + + $this->dbg(" --Searching on edge: ($x1,$y1)->($x2,$y2)"); + + $found=false; + $nn = count($edges); + for( $i=0; $i < $nn && !$found; ++$i ) { + $edge = $edges[$i]; + if( $found = ($x2==$edge[0][0] && $y2==$edge[0][1]) ) { + $polygons[$pol][] = array($edge[1][0],$edge[1][1]); + $x1 = $x2; $y1 = $y2; + $x2 = $edge[1][0]; $y2 = $edge[1][1]; + } + elseif( $found = ($x2==$edge[1][0] && $y2==$edge[1][1]) ) { + $polygons[$pol][] = array($edge[0][0],$edge[0][1]); + $x1 = $x2; $y1 = $y2; + $x2 = $edge[0][0]; $y2 = $edge[0][1]; + } + if( $found ) { + $this->dbg(" --Found next edge: [i=$i], (%,%) -> ($x2,$y2)"); + unset($edges[$i]); + $edges = array_values($edges); + } + } + + } while( $found ); + } + + if( !$found && count($edges)>0 ) { + $this->dbg("Searching on first vertice."); + list($x1,$y1) = $polygons[$pol][0]; + list($x2,$y2) = $polygons[$pol][1]; + + if( ! $this->IsVerticeOnBorder($x1,$y1) ) { + do { + + $this->dbg(" --Searching on edge: ($x1,$y1)->($x2,$y2)"); + + $found=false; + $nn = count($edges); + for( $i=0; $i < $nn && !$found; ++$i ) { + $edge = $edges[$i]; + if( $found = ($x1==$edge[0][0] && $y1==$edge[0][1]) ) { + array_unshift($polygons[$pol],array($edge[1][0],$edge[1][1])); + $x2 = $x1; $y2 = $y1; + $x1 = $edge[1][0]; $y1 = $edge[1][1]; + } + elseif( $found = ($x1==$edge[1][0] && $y1==$edge[1][1]) ) { + array_unshift($polygons[$pol],array($edge[0][0],$edge[0][1])); + $x2 = $x1; $y2 = $y1; + $x1 = $edge[0][0]; $y1 = $edge[0][1]; + } + if( $found ) { + $this->dbg(" --Found next edge: [i=$i], ($x1,$y1) -> (%,%)"); + unset($edges[$i]); + $edges = array_values($edges); + } + } + + } while( $found ); + } + + } + + $pol++; + } + } + + return $polygons; + } + +} +define('HORIZ_EDGE',0); +define('VERT_EDGE',1); + +class FillGridRect { + private $edges,$dataPoints,$colors,$isoBars; + private $invert=false; + + function __construct(&$edges,&$dataPoints,$isoBars,$colors) { + $this->edges = $edges; + $this->dataPoints = $dataPoints; + $this->colors = $colors; + $this->isoBars = $isoBars; + } + + function GetIsobarColor($val) { + for ($i = 0 ; $i < count($this->isoBars) ; $i++) { + if( $val <= $this->isoBars[$i] ) { + return $this->colors[$i]; + } + } + return $this->colors[$i]; // The color for all values above the highest isobar + } + + function GetIsobarVal($a,$b) { + // Get the isobar that is between the values a and b + // If there are more isobars then return the one with lowest index + if( $b < $a ) { + $t=$a; $a=$b; $b=$t; + } + $i = 0 ; + $n = count($this->isoBars); + while( $i < $n && $this->isoBars[$i] < $a ) { + ++$i; + } + if( $i >= $n ) + die("Internal error. Cannot find isobar values for ($a,$b)"); + return $this->isoBars[$i]; + } + + function getCrossingCoord($aRow,$aCol,$aEdgeDir,$aIsobarVal) { + // In order to avoid numerical problem when two vertices are very close + // we have to check and avoid dividing by close to zero denumerator. + if( $aEdgeDir == HORIZ_EDGE ) { + $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow][$aCol+1]); + if( $d > 0.001 ) { + $xcoord = $aCol + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; + } + else { + $xcoord = $aCol; + } + $ycoord = $aRow; + } + else { + $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow+1][$aCol]); + if( $d > 0.001 ) { + $ycoord = $aRow + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; + } + else { + $ycoord = $aRow; + } + $xcoord = $aCol; + } + if( $this->invert ) { + $ycoord = $this->nbrRows-1 - $ycoord; + } + return array($xcoord,$ycoord); + } + + function Fill(ContCanvas $canvas) { + + $nx_vertices = count($this->dataPoints[0]); + $ny_vertices = count($this->dataPoints); + + // Loop through all squares in the grid + for($col=0; $col < $nx_vertices-1; ++$col) { + for($row=0; $row < $ny_vertices-1; ++$row) { + + $n = 0;$quad_edges=array(); + if ( $this->edges[VERT_EDGE][$row][$col] ) $quad_edges[$n++] = array($row, $col, VERT_EDGE); + if ( $this->edges[VERT_EDGE][$row][$col+1] ) $quad_edges[$n++] = array($row, $col+1,VERT_EDGE); + if ( $this->edges[HORIZ_EDGE][$row][$col] ) $quad_edges[$n++] = array($row, $col, HORIZ_EDGE); + if ( $this->edges[HORIZ_EDGE][$row+1][$col] ) $quad_edges[$n++] = array($row+1,$col, HORIZ_EDGE); + + if( $n == 0 ) { + // Easy, fill the entire quadrant with one color since we have no crossings + // Select the top left datapoint as representing this quadrant + // color for this quadrant + $color = $this->GetIsobarColor($this->dataPoints[$row][$col]); + $polygon = array($col,$row,$col,$row+1,$col+1,$row+1,$col+1,$row,$col,$row); + $canvas->FilledPolygon($polygon,$color); + + } elseif( $n==2 ) { + + // There is one isobar edge crossing this quadrant. In order to fill we need to + // find out the orientation of the two areas this edge is separating in order to + // construct the two polygons that define the two areas to be filled + // There are six possible variants + // 0) North-South + // 1) West-East + // 2) West-North + // 3) East-North + // 4) West-South + // 5) East-South + $type=-1; + if( $this->edges[HORIZ_EDGE][$row][$col] ) { + if( $this->edges[HORIZ_EDGE][$row+1][$col] ) $type=0; // North-South + elseif( $this->edges[VERT_EDGE][$row][$col] ) $type=2; + elseif( $this->edges[VERT_EDGE][$row][$col+1] ) $type=3; + } + elseif( $this->edges[HORIZ_EDGE][$row+1][$col] ) { + if( $this->edges[VERT_EDGE][$row][$col] ) $type=4; + elseif( $this->edges[VERT_EDGE][$row][$col+1] ) $type=5; + } + else { + $type=1; + } + if( $type==-1 ) { + die('Internal error: n=2 but no edges in the quadrant was find to determine type.'); + } + + switch( $type ) { + case 0: //North-South + + // North vertice + $v1 = $this->dataPoints[$row][$col]; + $v2 = $this->dataPoints[$row][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x1,$y1) = $this->getCrossingCoord($row, $col,HORIZ_EDGE, $isobarValue); + + // South vertice + $v1 = $this->dataPoints[$row+1][$col]; + $v2 = $this->dataPoints[$row+1][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x2,$y2) = $this->getCrossingCoord($row+1, $col,HORIZ_EDGE, $isobarValue); + + $polygon = array($col,$row,$x1,$y1,$x2,$y2,$col,$row+1,$col,$row); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); + + $polygon = array($col+1,$row,$x1,$y1,$x2,$y2,$col+1,$row+1,$col+1,$row); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); + + break; + + case 1: // West-East + + // West vertice + $v1 = $this->dataPoints[$row][$col]; + $v2 = $this->dataPoints[$row+1][$col]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x1,$y1) = $this->getCrossingCoord($row, $col,VERT_EDGE, $isobarValue); + + // East vertice + $v1 = $this->dataPoints[$row][$col+1]; + $v2 = $this->dataPoints[$row+1][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x2,$y2) = $this->getCrossingCoord($row, $col+1,VERT_EDGE, $isobarValue); + + $polygon = array($col,$row,$x1,$y1,$x2,$y2,$col+1,$row,$col,$row); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); + + $polygon = array($col,$row+1,$x1,$y1,$x2,$y2,$col+1,$row+1,$col,$row+1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); + break; + + case 2: // West-North + + // West vertice + $v1 = $this->dataPoints[$row][$col]; + $v2 = $this->dataPoints[$row+1][$col]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x1,$y1) = $this->getCrossingCoord($row, $col,VERT_EDGE, $isobarValue); + + // North vertice + $v1 = $this->dataPoints[$row][$col]; + $v2 = $this->dataPoints[$row][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x2,$y2) = $this->getCrossingCoord($row, $col,HORIZ_EDGE, $isobarValue); + + $polygon = array($col,$row,$x1,$y1,$x2,$y2,$col,$row); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); + + $polygon = array($x1,$y1,$x2,$y2,$col+1,$row,$col+1,$row+1,$col,$row+1,$x1,$y1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); + + break; + + case 3: // East-North + + // if( $row==3 && $col==1 && $n==2 ) { + // echo " ** East-North
      "; + // } + + + // East vertice + $v1 = $this->dataPoints[$row][$col+1]; + $v2 = $this->dataPoints[$row+1][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x1,$y1) = $this->getCrossingCoord($row, $col+1,VERT_EDGE, $isobarValue); + // + // if( $row==3 && $col==1 && $n==2 ) { + // echo " ** E_val($v1,$v2), isobar=$isobarValue
      "; + // echo " ** E($x1,$y1)
      "; + // } + + + // North vertice + $v1 = $this->dataPoints[$row][$col]; + $v2 = $this->dataPoints[$row][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x2,$y2) = $this->getCrossingCoord($row, $col,HORIZ_EDGE, $isobarValue); + + // if( $row==3 && $col==1 && $n==2 ) { + // echo " ** N_val($v1,$v2), isobar=$isobarValue
      "; + // echo " ** N($x2,$y2)
      "; + // } + // if( $row==3 && $col==1 && $n==2 ) + // $canvas->Line($x1,$y1,$x2,$y2,'blue'); + + $polygon = array($x1,$y1,$x2,$y2,$col+1,$row,$x1,$y1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); + + $polygon = array($col,$row,$x2,$y2,$x1,$y1,$col+1,$row+1,$col,$row+1,$col,$row); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); + + break; + + case 4: // West-South + + // West vertice + $v1 = $this->dataPoints[$row][$col]; + $v2 = $this->dataPoints[$row+1][$col]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x1,$y1) = $this->getCrossingCoord($row, $col,VERT_EDGE, $isobarValue); + + // South vertice + $v1 = $this->dataPoints[$row+1][$col]; + $v2 = $this->dataPoints[$row+1][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x2,$y2) = $this->getCrossingCoord($row+1, $col,HORIZ_EDGE, $isobarValue); + + $polygon = array($col,$row+1,$x1,$y1,$x2,$y2,$col,$row+1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); + + $polygon = array($x1,$y1,$x2,$y2,$col+1,$row+1,$col+1,$row,$col,$row,$x1,$y1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); + + break; + + case 5: // East-South + + // + // if( $row==1 && $col==1 && $n==2 ) { + // echo " ** Sout-East
      "; + // } + + // East vertice + $v1 = $this->dataPoints[$row][$col+1]; + $v2 = $this->dataPoints[$row+1][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x1,$y1) = $this->getCrossingCoord($row, $col+1,VERT_EDGE, $isobarValue); + + // if( $row==1 && $col==1 && $n==2 ) { + // echo " ** E_val($v1,$v2), isobar=$isobarValue
      "; + // echo " ** E($x1,$y1)
      "; + // } + + // South vertice + $v1 = $this->dataPoints[$row+1][$col]; + $v2 = $this->dataPoints[$row+1][$col+1]; + $isobarValue = $this->GetIsobarVal($v1, $v2); + list($x2,$y2) = $this->getCrossingCoord($row+1, $col,HORIZ_EDGE, $isobarValue); + + // if( $row==1 && $col==1 && $n==2 ) { + // echo " ** S_val($v1,$v2), isobar=$isobarValue
      "; + // echo " ** S($x2,$y2)
      "; + // } + + $polygon = array($col+1,$row+1,$x1,$y1,$x2,$y2,$col+1,$row+1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v2)); + + $polygon = array($x1,$y1,$x2,$y2,$col,$row+1,$col,$row,$col+1,$row,$x1,$y1); + $canvas->FilledPolygon($polygon,$this->GetIsobarColor($v1)); + + break; + + } + + } + + } + } + + } +} + + +class ContCanvas { + public $g; + public $shape,$scale; + function __construct($xmax=6,$ymax=6,$width=400,$height=400) { + + $this->g = new CanvasGraph($width,$height); + $this->scale = new CanvasScale($this->g, 0, $xmax, 0, $ymax); + $this->shape = new Shape($this->g, $this->scale); + + //$this->g->SetFrame(true); + $this->g->SetMargin(5,5,5,5); + $this->g->SetMarginColor('white@1'); + $this->g->InitFrame(); + + + $this->shape->SetColor('gray'); + for( $col=1; $col<$xmax; ++$col ) { + $this->shape->Line($col, 0, $col, $ymax); + } + for( $row=1; $row<$ymax; ++$row ) { + $this->shape->Line(0, $row, $xmax, $row); + } + } + + function SetDatapoints($datapoints) { + $ny=count($datapoints); + $nx=count($datapoints[0]); + $t = new Text(); + $t->SetFont(FF_ARIAL,FS_NORMAL,8); + for( $x=0; $x < $nx; ++$x ) { + for( $y=0; $y < $ny; ++$y ) { + list($x1,$y1) = $this->scale->Translate($x,$y); + + if( $datapoints[$y][$x] > 0 ) + $t->SetColor('blue'); + else + $t->SetColor('black'); + $t->SetFont(FF_ARIAL,FS_BOLD,8); + $t->Set($datapoints[$y][$x]); + $t->Stroke($this->g->img,$x1,$y1); + + $t->SetColor('gray'); + $t->SetFont(FF_ARIAL,FS_NORMAL,8); + $t->Set("($y,$x)"); + $t->Stroke($this->g->img,$x1+10,$y1); + + } + } + } + + function DrawLinePolygons($p,$color='red') { + $this->shape->SetColor($color); + for ($i = 0 ; $i < count($p) ; $i++) { + $x1 = $p[$i][0][0]; $y1 = $p[$i][0][1]; + for ($j = 1 ; $j < count($p[$i]) ; $j++) { + $x2=$p[$i][$j][0]; $y2 = $p[$i][$j][1]; + $this->shape->Line($x1, $y1, $x2, $y2); + $x1=$x2; $y1=$y2; + } + } + } + + function Line($x1,$y1,$x2,$y2,$color='red') { + $this->shape->SetColor($color); + $this->shape->Line($x1, $y1, $x2, $y2); + } + function Polygon($p,$color='blue') { + $this->shape->SetColor($color); + $this->shape->Polygon($p); + } + + function FilledPolygon($p,$color='lightblue') { + $this->shape->SetColor($color); + $this->shape->FilledPolygon($p); + } + + function Point($x,$y,$color) { + list($x1,$y1) = $this->scale->Translate($x, $y); + $this->shape->SetColor($color); + $this->g->img->Point($x1,$y1); + } + + function Stroke() { + $this->g->Stroke(); + } + +} + + +class PixelFill { + + private $edges,$dataPoints,$colors,$isoBars; + + function __construct(&$edges,&$dataPoints,$isoBars,$colors) { + $this->edges = $edges; + $this->dataPoints = $dataPoints; + $this->colors = $colors; + $this->isoBars = $isoBars; + } + + function GetIsobarColor($val) { + for ($i = 0 ; $i < count($this->isoBars) ; $i++) { + if( $val <= $this->isoBars[$i] ) { + return $this->colors[$i]; + } + } + return $this->colors[$i]; // The color for all values above the highest isobar + } + + function Fill(ContCanvas $canvas) { + + $nx_vertices = count($this->dataPoints[0]); + $ny_vertices = count($this->dataPoints); + + // Loop through all squares in the grid + for($col=0; $col < $nx_vertices-1; ++$col) { + for($row=0; $row < $ny_vertices-1; ++$row) { + + $v=array( + $this->dataPoints[$row][$col], + $this->dataPoints[$row][$col+1], + $this->dataPoints[$row+1][$col+1], + $this->dataPoints[$row+1][$col], + ); + + list($x1,$y1) = $canvas->scale->Translate($col, $row); + list($x2,$y2) = $canvas->scale->Translate($col+1, $row+1); + + for( $x=$x1; $x < $x2; ++$x ) { + for( $y=$y1; $y < $y2; ++$y ) { + + $v1 = $v[0] + ($v[1]-$v[0])*($x-$x1)/($x2-$x1); + $v2 = $v[3] + ($v[2]-$v[3])*($x-$x1)/($x2-$x1); + $val = $v1 + ($v2-$v1)*($y-$y1)/($y2-$y1); + + if( $row==2 && $col==2 ) { + //echo " ($val ($x,$y)) (".$v[0].",".$v[1].",".$v[2].",".$v[3].")
      "; + } + $color = $this->GetIsobarColor($val); + $canvas->g->img->SetColor($color); + $canvas->g->img->Point($x, $y); + } + } + } + } + + } + +} + +$edges=array(array(),array(),array()); +$datapoints=array(); +for($col=0; $col<6; $col++) { + for($row=0; $row<6; $row++) { + $datapoints[$row][$col]=0; + $edges[VERT_EDGE][$row][$col] = false; + $edges[HORIZ_EDGE][$row][$col] = false; + } +} + +$datapoints[1][2] = 2; +$datapoints[2][1] = 1; +$datapoints[2][2] = 7; +$datapoints[2][3] = 2; +$datapoints[3][1] = 2; +$datapoints[3][2] = 17; +$datapoints[3][3] = 4; +$datapoints[4][2] = 3; + +$datapoints[1][4] = 12; + +$edges[VERT_EDGE][1][2] = true; +$edges[VERT_EDGE][3][2] = true; + +$edges[HORIZ_EDGE][2][1] = true; +$edges[HORIZ_EDGE][2][2] = true; +$edges[HORIZ_EDGE][3][1] = true; +$edges[HORIZ_EDGE][3][2] = true; + + + +$isobars = array(5,10,15); +$colors = array('lightgray','lightblue','lightred','red'); + +$engine = new PixelFill($edges, $datapoints, $isobars, $colors); +$canvas = new ContCanvas(); +$engine->Fill($canvas); +$canvas->SetDatapoints($datapoints); +$canvas->Stroke(); +die(); + + +//$tst = new Findpolygon(); +//$p1 = $tst->SetupTestData(); +// +//$canvas = new ContCanvas(); +//for ($i = 0 ; $i < count($tst->contourCoord); $i++) { +// $canvas->DrawLinePolygons($tst->contourCoord[$i]); +//} +// +//$p2 = $tst->FindPolygons(); +//for ($i = 0 ; $i < count($p2) ; $i++) { +// $canvas->FilledPolygon($tst->flattenEdges($p2[$i])); +//} +// +//for ($i = 0 ; $i < count($p2) ; $i++) { +// $canvas->Polygon($tst->flattenEdges($p2[$i])); +//} +// +//$canvas->Stroke(); +//die(); + + +//for( $trial = 0; $trial < 1; ++$trial ) { +// echo "\nTest $trial:\n"; +// echo "========================================\n"; +// $tst = new Findpolygon(); +// $p1 = $tst->SetupTestData(); +// +// // for ($i = 0 ; $i < count($p1) ; $i++) { +// // echo "Test polygon $i:\n"; +// // echo "---------------------\n"; +// // $tst->p_edges($tst->contourCoord[$i]); +// // echo "\n"; +// // } +// // +// $p2 = $tst->FindPolygons(); +// $npol = count($p2); +// //echo "\n** Found $npol separate polygon chains.\n\n"; +// +// for( $i=0; $i<$npol; ++$i ) { +// +// $res_forward = $tst->CompareCyclic($p1[$i], $p2[$i],true); +// $res_backward = $tst->CompareCyclic($p1[$i], $p2[$i],false); +// if( $res_backward || $res_forward ) { +// // if( $res_forward ) +// // echo "Forward matches!\n"; +// // else +// // echo "Backward matches!\n"; +// } +// else { +// echo "********** NO MATCH!!.\n\n"; +// echo "\nBefore find:\n"; +// for ($j = 0 ; $j < count($p1[$i]) ; $j++) { +// echo "(".$p1[$i][$j][0].','.$p1[$i][$j][1]."), "; +// } +// echo "\n"; +// +// echo "\nAfter find:\n"; +// for ($j = 0 ; $j < count($p2[$i]) ; $j++) { +// echo "(".$p2[$i][$j][0].','.$p2[$i][$j][1]."), "; +// } +// echo "\n"; +// } +// +// } +//} +// +//echo "\n\nAll tests ready.\n\n"; +// + + +?> diff --git a/ext/jpgraph-3.0.7/src/contour_dev/tri-quad.php b/ext/jpgraph-3.0.7/src/contour_dev/tri-quad.php index 4b321e1..067545f 100644 --- a/ext/jpgraph-3.0.7/src/contour_dev/tri-quad.php +++ b/ext/jpgraph-3.0.7/src/contour_dev/tri-quad.php @@ -1,790 +1,790 @@ -g = new CanvasGraph($width,$height); - $this->scale = new CanvasScale($this->g, 0, $xmax, 0, $ymax); - $this->shape = new Shape($this->g, $this->scale); - - //$this->g->SetFrame(true); - $this->g->SetMargin(2,2,2,2); - $this->g->SetMarginColor('white@1'); - $this->g->InitFrame(); - } - - function StrokeGrid() { - list($xmin,$xmax,$ymin,$ymax) = $this->scale->Get(); - $this->shape->SetColor('gray'); - for( $col=1; $col<$xmax; ++$col ) { - $this->shape->Line($col, 0, $col, $ymax); - } - for( $row=1; $row<$ymax; ++$row ) { - $this->shape->Line(0, $row, $xmax, $row); - } - } - - function SetDatapoints($datapoints) { - $ny=count($datapoints); - $nx=count($datapoints[0]); - $t = new Text(); - $t->SetFont(FF_ARIAL,FS_NORMAL,8); - for( $x=0; $x < $nx; ++$x ) { - for( $y=0; $y < $ny; ++$y ) { - list($x1,$y1) = $this->scale->Translate($x,$y); - - if( $datapoints[$y][$x] > 0 ) - $t->SetColor('blue'); - else - $t->SetColor('black'); - $t->SetFont(FF_ARIAL,FS_BOLD,8); - $t->Set($datapoints[$y][$x]); - $t->Stroke($this->g->img,$x1,$y1); - - $t->SetColor('gray'); - $t->SetFont(FF_ARIAL,FS_NORMAL,8); - $t->Set("($y,$x)"); - $t->Stroke($this->g->img,$x1+10,$y1); - - } - } - } - - function DrawLinePolygons($p,$color='red') { - $this->shape->SetColor($color); - for ($i = 0 ; $i < count($p) ; $i++) { - $x1 = $p[$i][0][0]; $y1 = $p[$i][0][1]; - for ($j = 1 ; $j < count($p[$i]) ; $j++) { - $x2=$p[$i][$j][0]; $y2 = $p[$i][$j][1]; - $this->shape->Line($x1, $y1, $x2, $y2); - $x1=$x2; $y1=$y2; - } - } - } - - function Line($x1,$y1,$x2,$y2,$color='red') { - $this->shape->SetColor($color); - $this->shape->Line($x1, $y1, $x2, $y2); - } - function Polygon($p,$color='blue') { - $this->shape->SetColor($color); - $this->shape->Polygon($p); - } - - function FilledPolygon($p,$color='lightblue') { - $this->shape->SetColor($color); - $this->shape->FilledPolygon($p); - } - - function Point($x,$y,$color) { - list($x1,$y1) = $this->scale->Translate($x, $y); - $this->shape->SetColor($color); - $this->g->img->Point($x1,$y1); - } - - function Stroke() { - $this->g->Stroke(); - } - -} - -// Calculate the area for a simple polygon. This will not work for -// non-simple polygons, i.e. self crossing. -function polygonArea($aX, $aY) { - $n = count($aX); - $area = 0 ; - $j = 0 ; - for ($i=0; $i < $n; $i++) { - $j++; - if ( $j == $n) { - $j=0; - } - $area += ($aX[i]+$aX[j])*($aY[i]-$aY[j]); - } - return area*.5; -} - -class SingleTestTriangle { - const contval=5; - static $maxdepth=2; - static $cnt=0; - static $t; - public $g; - public $shape,$scale; - public $cont = array(2,4,5); - public $contcolors = array('yellow','purple','seagreen','green','lightblue','blue','teal','orange','red','darkred','brown'); - public $dofill=false; - public $showtriangulation=false,$triangulation_color="lightgray"; - public $showannotation=false; - public $contlinecolor='black',$showcontlines=true; - private $labels = array(), $showlabels=false; - private $labelColor='black',$labelFF=FF_ARIAL,$labelFS=FS_BOLD,$labelFSize=9; - - function __construct($width,$height,$nx,$ny) { - $xmax=$nx+0.1;$ymax=$ny+0.1; - $this->g = new CanvasGraph($width,$height); - $this->scale = new CanvasScale($this->g, -0.1, $xmax, -0.1, $ymax); - $this->shape = new Shape($this->g, $this->scale); - - //$this->g->SetFrame(true); - $this->g->SetMargin(2,2,2,2); - $this->g->SetMarginColor('white@1'); - //$this->g->InitFrame(); - - self::$t = new Text(); - self::$t->SetColor('black'); - self::$t->SetFont(FF_ARIAL,FS_BOLD,9); - self::$t->SetAlign('center','center'); - } - - function getPlotSize() { - return array($this->g->img->width,$this->g->img->height); - } - - function SetContours($c) { - $this->cont = $c; - } - - function ShowLabels($aFlg=true) { - $this->showlabels = $aFlg; - } - - function ShowLines($aFlg=true) { - $this->showcontlines=$aFlg; - } - - function SetFilled($f=true) { - $this->dofill = $f; - } - - function ShowTriangulation($f=true) { - $this->showtriangulation = $f; - } - - function Stroke() { - $this->g->Stroke(); - } - - function FillPolygon($color,&$p) { - self::$cnt++; - if( $this->dofill ) { - $this->shape->SetColor($color); - $this->shape->FilledPolygon($p); - } - if( $this->showtriangulation ) { - $this->shape->SetColor($this->triangulation_color); - $this->shape->Polygon($p); - } - } - - function GetNextHigherContourIdx($val) { - for( $i=0; $i < count($this->cont); ++$i ) { - if( $val < $this->cont[$i] ) return $i; - } - return count($this->cont); - } - - function GetContVal($v1) { - for( $i=0; $i < count($this->cont); ++$i ) { - if( $this->cont[$i] > $v1 ) { - return $this->cont[$i]; - } - } - die('No contour value is larger or equal than : '.$v1); - } - - function GetColor($v) { - return $this->contcolors[$this->GetNextHigherContourIdx($v)]; - } - - function storeAnnotation($x1,$y1,$v1,$angle) { - $this->labels[$this->GetNextHigherContourIdx($v1)][] = array($x1,$y1,$v1,$angle); - } - - function labelProx($x1,$y1,$v1) { - - list($w,$h) = $this->getPlotSize(); - - - if( $x1 < 20 || $x1 > $w-20 ) - return true; - - if( $y1 < 20 || $y1 > $h-20 ) - return true; - - if( !isset ($this->labels[$this->GetNextHigherContourIdx($v1)]) ) { - return false; - } - $p = $this->labels[$this->GetNextHigherContourIdx($v1)]; - $n = count($p); - $d = 999999; - for ($i = 0 ; $i < $n ; $i++) { - $xp = $p[$i][0]; - $yp = $p[$i][1]; - $d = min($d, ($x1-$xp)*($x1-$xp) + ($y1-$yp)*($y1-$yp)); - } - - $limit = $w*$h/9; - $limit = max(min($limit,20000),3500); - if( $d < $limit ) return true; - else return false; - } - - function putLabel($x1,$y1,$x2,$y2,$v1) { - - $angle = 0; - if( $x2 - $x1 != 0 ) { - $grad = ($y2-$y1)/($x2-$x1); - $angle = -(atan($grad) * 180/M_PI); - self::$t->SetAngle($angle); - } - - $x = $this->scale->TranslateX($x1); - $y = $this->scale->TranslateY($y1); - if( !$this->labelProx($x, $y, $v1) ) { - $this->storeAnnotation($x, $y, $v1, $angle); - } - } - - function strokeLabels() { - $t = new Text(); - $t->SetColor($this->labelColor); - $t->SetFont($this->labelFF,$this->labelFS,$this->labelFSize); - $t->SetAlign('center','center'); - - foreach ($this->labels as $cont_idx => $pos) { - if( $cont_idx >= 10 ) return; - foreach ($pos as $idx => $coord) { - $t->Set( sprintf("%.1f",$coord[2]) ); - $t->SetAngle($coord[3]); - $t->Stroke($this->g->img,$coord[0],$coord[1]); - } - } - } - - function annotate($x1,$y1,$x2,$y2,$x1p,$y1p,$v1,$v2,$v1p) { - if( !$this->showannotation ) return; - /* - $this->g->img->SetColor('green'); - $this->g->img->FilledCircle($this->scale->TranslateX($x1),$this->scale->TranslateY($y1), 4); - $this->g->img->FilledCircle($this->scale->TranslateX($x2),$this->scale->TranslateY($y2), 4); - - $this->g->img->SetColor('red'); - $this->g->img->FilledCircle($this->scale->TranslateX($x1p),$this->scale->TranslateY($y1p), 4); -*/ - //self::$t->Set(sprintf("%.1f",$v1,$this->VC($v1))); - //self::$t->Stroke($this->g->img,$this->scale->TranslateX($x1),$this->scale->TranslateY($y1)); - //self::$t->Set(sprintf("%.1f",$v2,$this->VC($v2))); - //self::$t->Stroke($this->g->img,$this->scale->TranslateX($x2),$this->scale->TranslateY($y2)); - - $x = $this->scale->TranslateX($x1p); - $y = $this->scale->TranslateY($y1p); - if( !$this->labelProx($x, $y, $v1p) ) { - $this->storeAnnotation($x, $y, $v1p); - self::$t->Set(sprintf("%.1f",$v1p,$this->VC($v1p))); - self::$t->Stroke($this->g->img,$x,$y); - } - } - - function Pertubate(&$v1,&$v2,&$v3,&$v4) { - $pert = 0.9999; - $n = count($this->cont); - for($i=0; $i < $n; ++$i) { - if( $v1==$this->cont[$i] ) { - $v1 *= $pert; - break; - } - } - for($i=0; $i < $n; ++$i) { - if( $v2==$this->cont[$i] ) { - $v2 *= $pert; - break; - } - } - for($i=0; $i < $n; ++$i) { - if( $v3==$this->cont[$i] ) { - $v3 *= $pert; - break; - } - } - for($i=0; $i < $n; ++$i) { - if( $v4==$this->cont[$i] ) { - $v4 *= $pert; - break; - } - } - } - - function interp2($x1,$y1,$x2,$y2,$v1,$v2) { - $cv = $this->GetContVal(min($v1,$v2)); - $alpha = ($v1-$cv)/($v1-$v2); - $x1p = $x1*(1-$alpha) + $x2*$alpha; - $y1p = $y1*(1-$alpha) + $y2*$alpha; - $v1p = $v1 + $alpha*($v2-$v1); - return array($x1p,$y1p,$v1p); - } - - function RectFill($v1,$v2,$v3,$v4,$x1,$y1,$x2,$y2,$x3,$y3,$x4,$y4,$depth) { - if( $depth >= self::$maxdepth ) { - // Abort and just appoximate the color of this area - // with the average of the three values - $color = $this->GetColor(($v1+$v2+$v3+$v4)/4); - $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $x1, $y1); - $this->FillPolygon($color,$p) ; - } - else { - - $this->Pertubate($v1,$v2,$v3,$v4); - - $fcnt = 0 ; - $vv1 = $this->GetNextHigherContourIdx($v1); - $vv2 = $this->GetNextHigherContourIdx($v2); - $vv3 = $this->GetNextHigherContourIdx($v3); - $vv4 = $this->GetNextHigherContourIdx($v4); - $eps = 0.0001; - - if( $vv1 == $vv2 && $vv2 == $vv3 && $vv3 == $vv4 ) { - $color = $this->GetColor($v1); - $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $x1, $y1); - $this->FillPolygon($color,$p) ; - } - else { - - $dv1 = abs($vv1-$vv2); - $dv2 = abs($vv2-$vv3); - $dv3 = abs($vv3-$vv4); - $dv4 = abs($vv1-$vv4); - - if( $dv1 == 1 ) { - list($x1p,$y1p,$v1p) = $this->interp2($x1,$y1,$x2,$y2,$v1,$v2); - $fcnt++; - } - - if( $dv2 == 1 ) { - list($x2p,$y2p,$v2p) = $this->interp2($x2,$y2,$x3,$y3,$v2,$v3); - $fcnt++; - } - - if( $dv3 == 1 ) { - list($x3p,$y3p,$v3p) = $this->interp2($x3,$y3,$x4,$y4,$v3,$v4); - $fcnt++; - } - - if( $dv4 == 1 ) { - list($x4p,$y4p,$v4p) = $this->interp2($x4,$y4,$x1,$y1,$v4,$v1); - $fcnt++; - } - - $totdv = $dv1 + $dv2 + $dv3 + $dv4 ; - - if( ($fcnt == 2 && $totdv==2) || ($fcnt == 4 && $totdv==4) ) { - - if( $fcnt == 2 && $totdv==2 ) { - - if( $dv1 == 1 && $dv2 == 1) { - $color1 = $this->GetColor($v2); - $p1 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); - $color2 = $this->GetColor($v4); - $p2 = array($x1,$y1,$x1p,$y1p,$x2p,$y2p,$x3,$y3,$x4,$y4,$x1,$y1); - - $color = $this->GetColor($v1p); - $p = array($x1p,$y1p,$x2p,$y2p); - $v = $v1p; - } - elseif( $dv1 == 1 && $dv3 == 1 ) { - $color1 = $this->GetColor($v2); - $p1 = array($x1p,$y1p,$x2,$y2,$x3,$y3,$x3p,$y3p,$x1p,$y1p); - $color2 = $this->GetColor($v4); - $p2 = array($x1,$y1,$x1p,$y1p,$x3p,$y3p,$x4,$y4,$x1,$y1); - - $color = $this->GetColor($v1p); - $p = array($x1p,$y1p,$x3p,$y3p); - $v = $v1p; - } - elseif( $dv1 == 1 && $dv4 == 1 ) { - $color1 = $this->GetColor($v1); - $p1 = array($x1,$y1,$x1p,$y1p,$x4p,$y4p,$x1,$y1); - $color2 = $this->GetColor($v3); - $p2 = array($x1p,$y1p,$x2,$y2,$x3,$y3,$x4,$y4,$x4p,$y4p,$x1p,$y1p); - - $color = $this->GetColor($v1p); - $p = array($x1p,$y1p,$x4p,$y4p); - $v = $v1p; - } - elseif( $dv2 == 1 && $dv4 == 1 ) { - $color1 = $this->GetColor($v1); - $p1 = array($x1,$y1,$x2,$y2,$x2p,$y2p,$x4p,$y4p,$x1,$y1); - $color2 = $this->GetColor($v3); - $p2 = array($x4p,$y4p,$x2p,$y2p,$x3,$y3,$x4,$y4,$x4p,$y4p); - - $color = $this->GetColor($v2p); - $p = array($x2p,$y2p,$x4p,$y4p); - $v = $v2p; - } - elseif( $dv2 == 1 && $dv3 == 1 ) { - $color1 = $this->GetColor($v1); - $p1 = array($x1,$y1,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x4,$y4,$x1,$y1); - $color2 = $this->GetColor($v3); - $p2 = array($x2p,$y2p,$x3,$y3,$x3p,$y3p,$x2p,$y2p); - - $color = $this->GetColor($v2p); - $p = array($x2p,$y2p,$x3p,$y3p); - $v = $v2p; - } - elseif( $dv3 == 1 && $dv4 == 1 ) { - $color1 = $this->GetColor($v1); - $p1 = array($x1,$y1,$x2,$y2,$x3,$y3,$x3p,$y3p,$x4p,$y4p,$x1,$y1); - $color2 = $this->GetColor($v4); - $p2 = array($x4p,$y4p,$x3p,$y3p,$x4,$y4,$x4p,$y4p); - - $color = $this->GetColor($v4p); - $p = array($x4p,$y4p,$x3p,$y3p); - $v = $v4p; - } - - $this->FillPolygon($color1,$p1); - $this->FillPolygon($color2,$p2); - - if( $this->showcontlines ) { - if( $this->dofill ) { - $this->shape->SetColor($this->contlinecolor); - } - else { - $this->shape->SetColor($color); - } - $this->shape->Line($p[0],$p[1],$p[2],$p[3]); - } - if( $this->showlabels ) { - $this->putLabel( ($p[0]+$p[2])/2, ($p[1]+$p[3])/2, $p[2],$p[3] , $v); - } - } - elseif( $fcnt == 4 && $totdv==4 ) { - $vc = ($v1+$v2+$v3+$v4)/4; - - if( $v1p == $v2p && $v2p == $v3p && $v3p == $v4p ) { - // Four edge crossings (saddle point) of the same contour - // so we first need to - // find out how the saddle is crossing "/" or "\" - - if( $this->GetNextHigherContourIdx($vc) == $this->GetNextHigherContourIdx($v1) ) { - // "\" - $color1 = $this->GetColor($v1); - $p1 = array($x1,$y1,$x1p,$y1p,$x4p,$y4p,$x1,$y1); - - $color2 = $this->GetColor($v2); - $p2 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x4,$y4,$x4p,$y4p,$x1p,$y1p); - - $color3 = $color1; - $p3 = array($x2p,$y2p,$x3,$y3,$x3p,$y3p,$x2p,$y2p); - - $colorl1 = $this->GetColor($v1p); - $pl1 = array($x1p,$y1p,$x4p,$y4p); - $colorl2 = $this->GetColor($v2p); - $pl2 = array($x2p,$y2p,$x3p,$y3p); - $vl1 = $v1p; $vl2 = $v2p; - - } - else { - // "/" - $color1 = $this->GetColor($v2); - $p1 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); - - $color2 = $this->GetColor($v3); - $p2 = array($x1p,$y1p,$x2p,$y2p,$x3,$y3,$x3p,$y3p,$x4p,$y4p,$x1,$y1,$x1p,$y1p); - - $color3 = $color1; - $p3 = array($x4p,$y4p,$x3p,$y3p,$x4,$y4,$x4p,$y4p); - - $colorl1 = $this->GetColor($v1p); - $pl1 = array($x1p,$y1p,$x2p,$y2p); - $colorl2 = $this->GetColor($v4p); - $pl2 = array($x4p,$y4p,$x3p,$y3p); - $vl1 = $v1p; $vl2 = $v4p; - } - } - else { - // There are two different contours crossing so we need to find - // out which belongs to which - if( $v1p == $v2p ) { - // "/" - $color1 = $this->GetColor($v2); - $p1 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); - - $color2 = $this->GetColor($v3); - $p2 = array($x1p,$y1p,$x2p,$y2p,$x3,$y3,$x3p,$y3p,$x4p,$y4p,$x1,$y1,$x1p,$y1p); - - $color3 = $this->GetColor($v4); - $p3 = array($x4p,$y4p,$x3p,$y3p,$x4,$y4,$x4p,$y4p); - - $colorl1 = $this->GetColor($v1p); - $pl1 = array($x1p,$y1p,$x2p,$y2p); - $colorl2 = $this->GetColor($v4p); - $pl2 = array($x4p,$y4p,$x3p,$y3p); - $vl1 = $v1p; $vl2 = $v4p; - } - else { //( $v1p == $v4p ) - // "\" - $color1 = $this->GetColor($v1); - $p1 = array($x1,$y1,$x1p,$y1p,$x4p,$y4p,$x1,$y1); - - $color2 = $this->GetColor($v2); - $p2 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x4,$y4,$x4p,$y4p,$x1p,$y1p); - - $color3 = $this->GetColor($v3); - $p3 = array($x2p,$y2p,$x3,$y3,$x3p,$y3p,$x2p,$y2p); - - $colorl1 = $this->GetColor($v1p); - $pl1 = array($x1p,$y1p,$x4p,$y4p); - $colorl2 = $this->GetColor($v2p); - $pl2 = array($x2p,$y2p,$x3p,$y3p); - $vl1 = $v1p; $vl2 = $v2p; - } - } - $this->FillPolygon($color1,$p1); - $this->FillPolygon($color2,$p2); - $this->FillPolygon($color3,$p3); - - if( $this->showcontlines ) { - if( $this->dofill ) { - $this->shape->SetColor($this->contlinecolor); - $this->shape->Line($pl1[0],$pl1[1],$pl1[2],$pl1[3]); - $this->shape->Line($pl2[0],$pl2[1],$pl2[2],$pl2[3]); - } - else { - $this->shape->SetColor($colorl1); - $this->shape->Line($pl1[0],$pl1[1],$pl1[2],$pl1[3]); - $this->shape->SetColor($colorl2); - $this->shape->Line($pl2[0],$pl2[1],$pl2[2],$pl2[3]); - } - } - if( $this->showlabels ) { - $this->putLabel( ($pl1[0]+$pl1[2])/2, ($pl1[1]+$pl1[3])/2, $pl1[2], $pl1[3], $vl1); - $this->putLabel( ($pl2[0]+$pl2[2])/2, ($pl2[1]+$pl2[3])/2, $pl2[2], $pl2[3],$vl2); - } - } - } - else { - $vc = ($v1+$v2+$v3+$v4)/4; - $xc = ($x1+$x4)/2; - $yc = ($y1+$y2)/2; - - // Top left - $this->RectFill(($v1+$v2)/2, $v2, ($v2+$v3)/2, $vc, - $x1,$yc, $x2,$y2, $xc,$y2, $xc,$yc, $depth+1); - // Top right - $this->RectFill($vc, ($v2+$v3)/2, $v3, ($v3+$v4)/2, - $xc,$yc, $xc,$y2, $x3,$y3, $x3,$yc, $depth+1); - - // Bottom left - $this->RectFill($v1, ($v1+$v2)/2, $vc, ($v1+$v4)/2, - $x1,$y1, $x1,$yc, $xc,$yc, $xc,$y4, $depth+1); - - // Bottom right - $this->RectFill(($v1+$v4)/2, $vc, ($v3+$v4)/2, $v4, - $xc,$y1, $xc,$yc, $x3,$yc, $x4,$y4, $depth+1); - - } - } - } - } - - function TriFill($v1,$v2,$v3,$x1,$y1,$x2,$y2,$x3,$y3,$depth) { - if( $depth >= self::$maxdepth ) { - // Abort and just appoximate the color of this area - // with the average of the three values - $color = $this->GetColor(($v1+$v2+$v3)/3); - $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x1, $y1); - $this->FillPolygon($color,$p) ; - } - else { - // In order to avoid some real unpleasentness in case a vertice is exactly - // the same value as a contour we pertuberate them so that we do not end up - // in udefined situation. This will only affect the calculations and not the - // visual appearance - - $dummy=0; - $this->Pertubate($v1,$v2,$v3,$dummy); - - $fcnt = 0 ; - $vv1 = $this->GetNextHigherContourIdx($v1); - $vv2 = $this->GetNextHigherContourIdx($v2); - $vv3 = $this->GetNextHigherContourIdx($v3); - $eps = 0.0001; - - if( $vv1 == $vv2 && $vv2 == $vv3 ) { - $color = $this->GetColor($v1); - $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x1, $y1); - $this->FillPolygon($color,$p) ; - } - else { - $dv1 = abs($vv1-$vv2); - $dv2 = abs($vv2-$vv3); - $dv3 = abs($vv1-$vv3); - - if( $dv1 == 1 ) { - list($x1p,$y1p,$v1p) = $this->interp2($x1,$y1,$x2,$y2,$v1,$v2); - $fcnt++; - } - else { - $x1p = ($x1+$x2)/2; - $y1p = ($y1+$y2)/2; - $v1p = ($v1+$v2)/2; - } - - if( $dv2 == 1 ) { - list($x2p,$y2p,$v2p) = $this->interp2($x2,$y2,$x3,$y3,$v2,$v3); - $fcnt++; - } - else { - $x2p = ($x2+$x3)/2; - $y2p = ($y2+$y3)/2; - $v2p = ($v2+$v3)/2; - } - - if( $dv3 == 1 ) { - list($x3p,$y3p,$v3p) = $this->interp2($x3,$y3,$x1,$y1,$v3,$v1); - $fcnt++; - } - else { - $x3p = ($x3+$x1)/2; - $y3p = ($y3+$y1)/2; - $v3p = ($v3+$v1)/2; - } - - if( $fcnt == 2 && - ((abs($v1p-$v2p) < $eps && $dv1 ==1 && $dv2==1 ) || - (abs($v1p-$v3p) < $eps && $dv1 ==1 && $dv3==1 ) || - (abs($v2p-$v3p) < $eps && $dv2 ==1 && $dv3==1 )) ) { - - // This means that the contour line crosses exactly two sides - // and that the values of each vertice is such that only this - // contour line will cross this section. - // We can now be smart. The cotour line will simply divide the - // area in two polygons that we can fill and then return. There is no - // need to recurse. - - // First find out which two sides the contour is crossing - if( abs($v1p-$v2p) < $eps ) { - $p4 = array($x1,$y1,$x1p,$y1p,$x2p,$y2p,$x3,$y3,$x1,$y1); - $color4 = $this->GetColor($v1); - - $p3 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); - $color3 = $this->GetColor($v2); - - $p = array($x1p,$y1p,$x2p,$y2p); - $color = $this->GetColor($v1p); - $v = $v1p; - } - elseif( abs($v1p-$v3p) < $eps ) { - $p4 = array($x1p,$y1p,$x2,$y2,$x3,$y3,$x3p,$y3p,$x1p,$y1p); - $color4 = $this->GetColor($v2); - - $p3 = array($x1,$y1,$x1p,$y1p,$x3p,$y3p,$x1,$y1); - $color3 = $this->GetColor($v1); - - $p = array($x1p,$y1p,$x3p,$y3p); - $color = $this->GetColor($v1p); - $v = $v1p; - } - else { - $p4 = array($x1,$y1,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x1,$y1); - $color4 = $this->GetColor($v2); - - $p3 = array($x3p,$y3p,$x2p,$y2p,$x3,$y3,$x3p,$y3p); - $color3 = $this->GetColor($v3); - - $p = array($x3p,$y3p,$x2p,$y2p); - $color = $this->GetColor($v3p); - $v = $v3p; - } - $this->FillPolygon($color4,$p4); - $this->FillPolygon($color3,$p3); - - if( $this->showcontlines ) { - if( $this->dofill ) { - $this->shape->SetColor($this->contlinecolor); - } - else { - $this->shape->SetColor($color); - } - $this->shape->Line($p[0],$p[1],$p[2],$p[3]); - } - if( $this->showlabels ) { - $this->putLabel( ($p[0]+$p[2])/2, ($p[1]+$p[3])/2, $p[2], $p[3], $v); - } - } - else { - $this->TriFill($v1, $v1p, $v3p, $x1, $y1, $x1p, $y1p, $x3p, $y3p, $depth+1); - $this->TriFill($v1p, $v2, $v2p, $x1p, $y1p, $x2, $y2, $x2p, $y2p, $depth+1); - $this->TriFill($v3p, $v1p, $v2p, $x3p, $y3p, $x1p, $y1p, $x2p, $y2p, $depth+1); - $this->TriFill($v3p, $v2p, $v3, $x3p, $y3p, $x2p, $y2p, $x3, $y3, $depth+1); - } - } - } - } - - function Fill($v1,$v2,$v3,$maxdepth) { - $x1=0; $y1=1; - $x2=1; $y2=0; - $x3=1; $y3=1; - self::$maxdepth = $maxdepth; - $this->TriFill($v1, $v2, $v3, $x1, $y1, $x2, $y2, $x3, $y3, 0); - } - - function Fillmesh($meshdata,$maxdepth,$method='tri') { - $nx = count($meshdata[0]); - $ny = count($meshdata); - self::$maxdepth = $maxdepth; - for( $x=0; $x < $nx-1; ++$x ) { - for( $y=0; $y < $ny-1; ++$y ) { - $v1 = $meshdata[$y][$x]; - $v2 = $meshdata[$y][$x+1]; - $v3 = $meshdata[$y+1][$x+1]; - $v4 = $meshdata[$y+1][$x]; - - if( $method == 'tri' ) { - // Fill upper and lower triangle - $this->TriFill($v4, $v1, $v2, $x, $y+1, $x, $y, $x+1, $y, 0); - $this->TriFill($v4, $v2, $v3, $x, $y+1, $x+1, $y, $x+1, $y+1, 0); - } - else { - $this->RectFill($v4, $v1, $v2, $v3, $x, $y+1, $x, $y, $x+1, $y, $x+1, $y+1, 0); - } - } - } - if( $this->showlabels ) { - $this->strokeLabels(); - } - } -} - -$meshdata = array( - array (12,12,10,10), - array (10,10,8,14), - array (7,7,13,17), - array (4,5,8,12), - array (10,8,7,8)); - -$tt = new SingleTestTriangle(400,400,count($meshdata[0])-1,count($meshdata)-1); -$tt->SetContours(array(4.7, 6.0, 7.2, 8.6, 9.9, 11.2, 12.5, 13.8, 15.1, 16.4)); -$tt->SetFilled(true); - -//$tt->ShowTriangulation(true); -$tt->ShowLines(true); - -//$tt->ShowLabels(true); -$tt->Fillmesh($meshdata, 8, 'rect'); - -//$tt->Fill(4.0,3.0,7.0, 4); -//$tt->Fill(7,4,1,5); -//$tt->Fill(1,7,4,5); - -$tt->Stroke(); - -?> +g = new CanvasGraph($width,$height); + $this->scale = new CanvasScale($this->g, 0, $xmax, 0, $ymax); + $this->shape = new Shape($this->g, $this->scale); + + //$this->g->SetFrame(true); + $this->g->SetMargin(2,2,2,2); + $this->g->SetMarginColor('white@1'); + $this->g->InitFrame(); + } + + function StrokeGrid() { + list($xmin,$xmax,$ymin,$ymax) = $this->scale->Get(); + $this->shape->SetColor('gray'); + for( $col=1; $col<$xmax; ++$col ) { + $this->shape->Line($col, 0, $col, $ymax); + } + for( $row=1; $row<$ymax; ++$row ) { + $this->shape->Line(0, $row, $xmax, $row); + } + } + + function SetDatapoints($datapoints) { + $ny=count($datapoints); + $nx=count($datapoints[0]); + $t = new Text(); + $t->SetFont(FF_ARIAL,FS_NORMAL,8); + for( $x=0; $x < $nx; ++$x ) { + for( $y=0; $y < $ny; ++$y ) { + list($x1,$y1) = $this->scale->Translate($x,$y); + + if( $datapoints[$y][$x] > 0 ) + $t->SetColor('blue'); + else + $t->SetColor('black'); + $t->SetFont(FF_ARIAL,FS_BOLD,8); + $t->Set($datapoints[$y][$x]); + $t->Stroke($this->g->img,$x1,$y1); + + $t->SetColor('gray'); + $t->SetFont(FF_ARIAL,FS_NORMAL,8); + $t->Set("($y,$x)"); + $t->Stroke($this->g->img,$x1+10,$y1); + + } + } + } + + function DrawLinePolygons($p,$color='red') { + $this->shape->SetColor($color); + for ($i = 0 ; $i < count($p) ; $i++) { + $x1 = $p[$i][0][0]; $y1 = $p[$i][0][1]; + for ($j = 1 ; $j < count($p[$i]) ; $j++) { + $x2=$p[$i][$j][0]; $y2 = $p[$i][$j][1]; + $this->shape->Line($x1, $y1, $x2, $y2); + $x1=$x2; $y1=$y2; + } + } + } + + function Line($x1,$y1,$x2,$y2,$color='red') { + $this->shape->SetColor($color); + $this->shape->Line($x1, $y1, $x2, $y2); + } + function Polygon($p,$color='blue') { + $this->shape->SetColor($color); + $this->shape->Polygon($p); + } + + function FilledPolygon($p,$color='lightblue') { + $this->shape->SetColor($color); + $this->shape->FilledPolygon($p); + } + + function Point($x,$y,$color) { + list($x1,$y1) = $this->scale->Translate($x, $y); + $this->shape->SetColor($color); + $this->g->img->Point($x1,$y1); + } + + function Stroke() { + $this->g->Stroke(); + } + +} + +// Calculate the area for a simple polygon. This will not work for +// non-simple polygons, i.e. self crossing. +function polygonArea($aX, $aY) { + $n = count($aX); + $area = 0 ; + $j = 0 ; + for ($i=0; $i < $n; $i++) { + $j++; + if ( $j == $n) { + $j=0; + } + $area += ($aX[i]+$aX[j])*($aY[i]-$aY[j]); + } + return area*.5; +} + +class SingleTestTriangle { + const contval=5; + static $maxdepth=2; + static $cnt=0; + static $t; + public $g; + public $shape,$scale; + public $cont = array(2,4,5); + public $contcolors = array('yellow','purple','seagreen','green','lightblue','blue','teal','orange','red','darkred','brown'); + public $dofill=false; + public $showtriangulation=false,$triangulation_color="lightgray"; + public $showannotation=false; + public $contlinecolor='black',$showcontlines=true; + private $labels = array(), $showlabels=false; + private $labelColor='black',$labelFF=FF_ARIAL,$labelFS=FS_BOLD,$labelFSize=9; + + function __construct($width,$height,$nx,$ny) { + $xmax=$nx+0.1;$ymax=$ny+0.1; + $this->g = new CanvasGraph($width,$height); + $this->scale = new CanvasScale($this->g, -0.1, $xmax, -0.1, $ymax); + $this->shape = new Shape($this->g, $this->scale); + + //$this->g->SetFrame(true); + $this->g->SetMargin(2,2,2,2); + $this->g->SetMarginColor('white@1'); + //$this->g->InitFrame(); + + self::$t = new Text(); + self::$t->SetColor('black'); + self::$t->SetFont(FF_ARIAL,FS_BOLD,9); + self::$t->SetAlign('center','center'); + } + + function getPlotSize() { + return array($this->g->img->width,$this->g->img->height); + } + + function SetContours($c) { + $this->cont = $c; + } + + function ShowLabels($aFlg=true) { + $this->showlabels = $aFlg; + } + + function ShowLines($aFlg=true) { + $this->showcontlines=$aFlg; + } + + function SetFilled($f=true) { + $this->dofill = $f; + } + + function ShowTriangulation($f=true) { + $this->showtriangulation = $f; + } + + function Stroke() { + $this->g->Stroke(); + } + + function FillPolygon($color,&$p) { + self::$cnt++; + if( $this->dofill ) { + $this->shape->SetColor($color); + $this->shape->FilledPolygon($p); + } + if( $this->showtriangulation ) { + $this->shape->SetColor($this->triangulation_color); + $this->shape->Polygon($p); + } + } + + function GetNextHigherContourIdx($val) { + for( $i=0; $i < count($this->cont); ++$i ) { + if( $val < $this->cont[$i] ) return $i; + } + return count($this->cont); + } + + function GetContVal($v1) { + for( $i=0; $i < count($this->cont); ++$i ) { + if( $this->cont[$i] > $v1 ) { + return $this->cont[$i]; + } + } + die('No contour value is larger or equal than : '.$v1); + } + + function GetColor($v) { + return $this->contcolors[$this->GetNextHigherContourIdx($v)]; + } + + function storeAnnotation($x1,$y1,$v1,$angle) { + $this->labels[$this->GetNextHigherContourIdx($v1)][] = array($x1,$y1,$v1,$angle); + } + + function labelProx($x1,$y1,$v1) { + + list($w,$h) = $this->getPlotSize(); + + + if( $x1 < 20 || $x1 > $w-20 ) + return true; + + if( $y1 < 20 || $y1 > $h-20 ) + return true; + + if( !isset ($this->labels[$this->GetNextHigherContourIdx($v1)]) ) { + return false; + } + $p = $this->labels[$this->GetNextHigherContourIdx($v1)]; + $n = count($p); + $d = 999999; + for ($i = 0 ; $i < $n ; $i++) { + $xp = $p[$i][0]; + $yp = $p[$i][1]; + $d = min($d, ($x1-$xp)*($x1-$xp) + ($y1-$yp)*($y1-$yp)); + } + + $limit = $w*$h/9; + $limit = max(min($limit,20000),3500); + if( $d < $limit ) return true; + else return false; + } + + function putLabel($x1,$y1,$x2,$y2,$v1) { + + $angle = 0; + if( $x2 - $x1 != 0 ) { + $grad = ($y2-$y1)/($x2-$x1); + $angle = -(atan($grad) * 180/M_PI); + self::$t->SetAngle($angle); + } + + $x = $this->scale->TranslateX($x1); + $y = $this->scale->TranslateY($y1); + if( !$this->labelProx($x, $y, $v1) ) { + $this->storeAnnotation($x, $y, $v1, $angle); + } + } + + function strokeLabels() { + $t = new Text(); + $t->SetColor($this->labelColor); + $t->SetFont($this->labelFF,$this->labelFS,$this->labelFSize); + $t->SetAlign('center','center'); + + foreach ($this->labels as $cont_idx => $pos) { + if( $cont_idx >= 10 ) return; + foreach ($pos as $idx => $coord) { + $t->Set( sprintf("%.1f",$coord[2]) ); + $t->SetAngle($coord[3]); + $t->Stroke($this->g->img,$coord[0],$coord[1]); + } + } + } + + function annotate($x1,$y1,$x2,$y2,$x1p,$y1p,$v1,$v2,$v1p) { + if( !$this->showannotation ) return; + /* + $this->g->img->SetColor('green'); + $this->g->img->FilledCircle($this->scale->TranslateX($x1),$this->scale->TranslateY($y1), 4); + $this->g->img->FilledCircle($this->scale->TranslateX($x2),$this->scale->TranslateY($y2), 4); + + $this->g->img->SetColor('red'); + $this->g->img->FilledCircle($this->scale->TranslateX($x1p),$this->scale->TranslateY($y1p), 4); +*/ + //self::$t->Set(sprintf("%.1f",$v1,$this->VC($v1))); + //self::$t->Stroke($this->g->img,$this->scale->TranslateX($x1),$this->scale->TranslateY($y1)); + //self::$t->Set(sprintf("%.1f",$v2,$this->VC($v2))); + //self::$t->Stroke($this->g->img,$this->scale->TranslateX($x2),$this->scale->TranslateY($y2)); + + $x = $this->scale->TranslateX($x1p); + $y = $this->scale->TranslateY($y1p); + if( !$this->labelProx($x, $y, $v1p) ) { + $this->storeAnnotation($x, $y, $v1p); + self::$t->Set(sprintf("%.1f",$v1p,$this->VC($v1p))); + self::$t->Stroke($this->g->img,$x,$y); + } + } + + function Pertubate(&$v1,&$v2,&$v3,&$v4) { + $pert = 0.9999; + $n = count($this->cont); + for($i=0; $i < $n; ++$i) { + if( $v1==$this->cont[$i] ) { + $v1 *= $pert; + break; + } + } + for($i=0; $i < $n; ++$i) { + if( $v2==$this->cont[$i] ) { + $v2 *= $pert; + break; + } + } + for($i=0; $i < $n; ++$i) { + if( $v3==$this->cont[$i] ) { + $v3 *= $pert; + break; + } + } + for($i=0; $i < $n; ++$i) { + if( $v4==$this->cont[$i] ) { + $v4 *= $pert; + break; + } + } + } + + function interp2($x1,$y1,$x2,$y2,$v1,$v2) { + $cv = $this->GetContVal(min($v1,$v2)); + $alpha = ($v1-$cv)/($v1-$v2); + $x1p = $x1*(1-$alpha) + $x2*$alpha; + $y1p = $y1*(1-$alpha) + $y2*$alpha; + $v1p = $v1 + $alpha*($v2-$v1); + return array($x1p,$y1p,$v1p); + } + + function RectFill($v1,$v2,$v3,$v4,$x1,$y1,$x2,$y2,$x3,$y3,$x4,$y4,$depth) { + if( $depth >= self::$maxdepth ) { + // Abort and just appoximate the color of this area + // with the average of the three values + $color = $this->GetColor(($v1+$v2+$v3+$v4)/4); + $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $x1, $y1); + $this->FillPolygon($color,$p) ; + } + else { + + $this->Pertubate($v1,$v2,$v3,$v4); + + $fcnt = 0 ; + $vv1 = $this->GetNextHigherContourIdx($v1); + $vv2 = $this->GetNextHigherContourIdx($v2); + $vv3 = $this->GetNextHigherContourIdx($v3); + $vv4 = $this->GetNextHigherContourIdx($v4); + $eps = 0.0001; + + if( $vv1 == $vv2 && $vv2 == $vv3 && $vv3 == $vv4 ) { + $color = $this->GetColor($v1); + $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $x1, $y1); + $this->FillPolygon($color,$p) ; + } + else { + + $dv1 = abs($vv1-$vv2); + $dv2 = abs($vv2-$vv3); + $dv3 = abs($vv3-$vv4); + $dv4 = abs($vv1-$vv4); + + if( $dv1 == 1 ) { + list($x1p,$y1p,$v1p) = $this->interp2($x1,$y1,$x2,$y2,$v1,$v2); + $fcnt++; + } + + if( $dv2 == 1 ) { + list($x2p,$y2p,$v2p) = $this->interp2($x2,$y2,$x3,$y3,$v2,$v3); + $fcnt++; + } + + if( $dv3 == 1 ) { + list($x3p,$y3p,$v3p) = $this->interp2($x3,$y3,$x4,$y4,$v3,$v4); + $fcnt++; + } + + if( $dv4 == 1 ) { + list($x4p,$y4p,$v4p) = $this->interp2($x4,$y4,$x1,$y1,$v4,$v1); + $fcnt++; + } + + $totdv = $dv1 + $dv2 + $dv3 + $dv4 ; + + if( ($fcnt == 2 && $totdv==2) || ($fcnt == 4 && $totdv==4) ) { + + if( $fcnt == 2 && $totdv==2 ) { + + if( $dv1 == 1 && $dv2 == 1) { + $color1 = $this->GetColor($v2); + $p1 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); + $color2 = $this->GetColor($v4); + $p2 = array($x1,$y1,$x1p,$y1p,$x2p,$y2p,$x3,$y3,$x4,$y4,$x1,$y1); + + $color = $this->GetColor($v1p); + $p = array($x1p,$y1p,$x2p,$y2p); + $v = $v1p; + } + elseif( $dv1 == 1 && $dv3 == 1 ) { + $color1 = $this->GetColor($v2); + $p1 = array($x1p,$y1p,$x2,$y2,$x3,$y3,$x3p,$y3p,$x1p,$y1p); + $color2 = $this->GetColor($v4); + $p2 = array($x1,$y1,$x1p,$y1p,$x3p,$y3p,$x4,$y4,$x1,$y1); + + $color = $this->GetColor($v1p); + $p = array($x1p,$y1p,$x3p,$y3p); + $v = $v1p; + } + elseif( $dv1 == 1 && $dv4 == 1 ) { + $color1 = $this->GetColor($v1); + $p1 = array($x1,$y1,$x1p,$y1p,$x4p,$y4p,$x1,$y1); + $color2 = $this->GetColor($v3); + $p2 = array($x1p,$y1p,$x2,$y2,$x3,$y3,$x4,$y4,$x4p,$y4p,$x1p,$y1p); + + $color = $this->GetColor($v1p); + $p = array($x1p,$y1p,$x4p,$y4p); + $v = $v1p; + } + elseif( $dv2 == 1 && $dv4 == 1 ) { + $color1 = $this->GetColor($v1); + $p1 = array($x1,$y1,$x2,$y2,$x2p,$y2p,$x4p,$y4p,$x1,$y1); + $color2 = $this->GetColor($v3); + $p2 = array($x4p,$y4p,$x2p,$y2p,$x3,$y3,$x4,$y4,$x4p,$y4p); + + $color = $this->GetColor($v2p); + $p = array($x2p,$y2p,$x4p,$y4p); + $v = $v2p; + } + elseif( $dv2 == 1 && $dv3 == 1 ) { + $color1 = $this->GetColor($v1); + $p1 = array($x1,$y1,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x4,$y4,$x1,$y1); + $color2 = $this->GetColor($v3); + $p2 = array($x2p,$y2p,$x3,$y3,$x3p,$y3p,$x2p,$y2p); + + $color = $this->GetColor($v2p); + $p = array($x2p,$y2p,$x3p,$y3p); + $v = $v2p; + } + elseif( $dv3 == 1 && $dv4 == 1 ) { + $color1 = $this->GetColor($v1); + $p1 = array($x1,$y1,$x2,$y2,$x3,$y3,$x3p,$y3p,$x4p,$y4p,$x1,$y1); + $color2 = $this->GetColor($v4); + $p2 = array($x4p,$y4p,$x3p,$y3p,$x4,$y4,$x4p,$y4p); + + $color = $this->GetColor($v4p); + $p = array($x4p,$y4p,$x3p,$y3p); + $v = $v4p; + } + + $this->FillPolygon($color1,$p1); + $this->FillPolygon($color2,$p2); + + if( $this->showcontlines ) { + if( $this->dofill ) { + $this->shape->SetColor($this->contlinecolor); + } + else { + $this->shape->SetColor($color); + } + $this->shape->Line($p[0],$p[1],$p[2],$p[3]); + } + if( $this->showlabels ) { + $this->putLabel( ($p[0]+$p[2])/2, ($p[1]+$p[3])/2, $p[2],$p[3] , $v); + } + } + elseif( $fcnt == 4 && $totdv==4 ) { + $vc = ($v1+$v2+$v3+$v4)/4; + + if( $v1p == $v2p && $v2p == $v3p && $v3p == $v4p ) { + // Four edge crossings (saddle point) of the same contour + // so we first need to + // find out how the saddle is crossing "/" or "\" + + if( $this->GetNextHigherContourIdx($vc) == $this->GetNextHigherContourIdx($v1) ) { + // "\" + $color1 = $this->GetColor($v1); + $p1 = array($x1,$y1,$x1p,$y1p,$x4p,$y4p,$x1,$y1); + + $color2 = $this->GetColor($v2); + $p2 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x4,$y4,$x4p,$y4p,$x1p,$y1p); + + $color3 = $color1; + $p3 = array($x2p,$y2p,$x3,$y3,$x3p,$y3p,$x2p,$y2p); + + $colorl1 = $this->GetColor($v1p); + $pl1 = array($x1p,$y1p,$x4p,$y4p); + $colorl2 = $this->GetColor($v2p); + $pl2 = array($x2p,$y2p,$x3p,$y3p); + $vl1 = $v1p; $vl2 = $v2p; + + } + else { + // "/" + $color1 = $this->GetColor($v2); + $p1 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); + + $color2 = $this->GetColor($v3); + $p2 = array($x1p,$y1p,$x2p,$y2p,$x3,$y3,$x3p,$y3p,$x4p,$y4p,$x1,$y1,$x1p,$y1p); + + $color3 = $color1; + $p3 = array($x4p,$y4p,$x3p,$y3p,$x4,$y4,$x4p,$y4p); + + $colorl1 = $this->GetColor($v1p); + $pl1 = array($x1p,$y1p,$x2p,$y2p); + $colorl2 = $this->GetColor($v4p); + $pl2 = array($x4p,$y4p,$x3p,$y3p); + $vl1 = $v1p; $vl2 = $v4p; + } + } + else { + // There are two different contours crossing so we need to find + // out which belongs to which + if( $v1p == $v2p ) { + // "/" + $color1 = $this->GetColor($v2); + $p1 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); + + $color2 = $this->GetColor($v3); + $p2 = array($x1p,$y1p,$x2p,$y2p,$x3,$y3,$x3p,$y3p,$x4p,$y4p,$x1,$y1,$x1p,$y1p); + + $color3 = $this->GetColor($v4); + $p3 = array($x4p,$y4p,$x3p,$y3p,$x4,$y4,$x4p,$y4p); + + $colorl1 = $this->GetColor($v1p); + $pl1 = array($x1p,$y1p,$x2p,$y2p); + $colorl2 = $this->GetColor($v4p); + $pl2 = array($x4p,$y4p,$x3p,$y3p); + $vl1 = $v1p; $vl2 = $v4p; + } + else { //( $v1p == $v4p ) + // "\" + $color1 = $this->GetColor($v1); + $p1 = array($x1,$y1,$x1p,$y1p,$x4p,$y4p,$x1,$y1); + + $color2 = $this->GetColor($v2); + $p2 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x4,$y4,$x4p,$y4p,$x1p,$y1p); + + $color3 = $this->GetColor($v3); + $p3 = array($x2p,$y2p,$x3,$y3,$x3p,$y3p,$x2p,$y2p); + + $colorl1 = $this->GetColor($v1p); + $pl1 = array($x1p,$y1p,$x4p,$y4p); + $colorl2 = $this->GetColor($v2p); + $pl2 = array($x2p,$y2p,$x3p,$y3p); + $vl1 = $v1p; $vl2 = $v2p; + } + } + $this->FillPolygon($color1,$p1); + $this->FillPolygon($color2,$p2); + $this->FillPolygon($color3,$p3); + + if( $this->showcontlines ) { + if( $this->dofill ) { + $this->shape->SetColor($this->contlinecolor); + $this->shape->Line($pl1[0],$pl1[1],$pl1[2],$pl1[3]); + $this->shape->Line($pl2[0],$pl2[1],$pl2[2],$pl2[3]); + } + else { + $this->shape->SetColor($colorl1); + $this->shape->Line($pl1[0],$pl1[1],$pl1[2],$pl1[3]); + $this->shape->SetColor($colorl2); + $this->shape->Line($pl2[0],$pl2[1],$pl2[2],$pl2[3]); + } + } + if( $this->showlabels ) { + $this->putLabel( ($pl1[0]+$pl1[2])/2, ($pl1[1]+$pl1[3])/2, $pl1[2], $pl1[3], $vl1); + $this->putLabel( ($pl2[0]+$pl2[2])/2, ($pl2[1]+$pl2[3])/2, $pl2[2], $pl2[3],$vl2); + } + } + } + else { + $vc = ($v1+$v2+$v3+$v4)/4; + $xc = ($x1+$x4)/2; + $yc = ($y1+$y2)/2; + + // Top left + $this->RectFill(($v1+$v2)/2, $v2, ($v2+$v3)/2, $vc, + $x1,$yc, $x2,$y2, $xc,$y2, $xc,$yc, $depth+1); + // Top right + $this->RectFill($vc, ($v2+$v3)/2, $v3, ($v3+$v4)/2, + $xc,$yc, $xc,$y2, $x3,$y3, $x3,$yc, $depth+1); + + // Bottom left + $this->RectFill($v1, ($v1+$v2)/2, $vc, ($v1+$v4)/2, + $x1,$y1, $x1,$yc, $xc,$yc, $xc,$y4, $depth+1); + + // Bottom right + $this->RectFill(($v1+$v4)/2, $vc, ($v3+$v4)/2, $v4, + $xc,$y1, $xc,$yc, $x3,$yc, $x4,$y4, $depth+1); + + } + } + } + } + + function TriFill($v1,$v2,$v3,$x1,$y1,$x2,$y2,$x3,$y3,$depth) { + if( $depth >= self::$maxdepth ) { + // Abort and just appoximate the color of this area + // with the average of the three values + $color = $this->GetColor(($v1+$v2+$v3)/3); + $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x1, $y1); + $this->FillPolygon($color,$p) ; + } + else { + // In order to avoid some real unpleasentness in case a vertice is exactly + // the same value as a contour we pertuberate them so that we do not end up + // in udefined situation. This will only affect the calculations and not the + // visual appearance + + $dummy=0; + $this->Pertubate($v1,$v2,$v3,$dummy); + + $fcnt = 0 ; + $vv1 = $this->GetNextHigherContourIdx($v1); + $vv2 = $this->GetNextHigherContourIdx($v2); + $vv3 = $this->GetNextHigherContourIdx($v3); + $eps = 0.0001; + + if( $vv1 == $vv2 && $vv2 == $vv3 ) { + $color = $this->GetColor($v1); + $p = array($x1, $y1, $x2, $y2, $x3, $y3, $x1, $y1); + $this->FillPolygon($color,$p) ; + } + else { + $dv1 = abs($vv1-$vv2); + $dv2 = abs($vv2-$vv3); + $dv3 = abs($vv1-$vv3); + + if( $dv1 == 1 ) { + list($x1p,$y1p,$v1p) = $this->interp2($x1,$y1,$x2,$y2,$v1,$v2); + $fcnt++; + } + else { + $x1p = ($x1+$x2)/2; + $y1p = ($y1+$y2)/2; + $v1p = ($v1+$v2)/2; + } + + if( $dv2 == 1 ) { + list($x2p,$y2p,$v2p) = $this->interp2($x2,$y2,$x3,$y3,$v2,$v3); + $fcnt++; + } + else { + $x2p = ($x2+$x3)/2; + $y2p = ($y2+$y3)/2; + $v2p = ($v2+$v3)/2; + } + + if( $dv3 == 1 ) { + list($x3p,$y3p,$v3p) = $this->interp2($x3,$y3,$x1,$y1,$v3,$v1); + $fcnt++; + } + else { + $x3p = ($x3+$x1)/2; + $y3p = ($y3+$y1)/2; + $v3p = ($v3+$v1)/2; + } + + if( $fcnt == 2 && + ((abs($v1p-$v2p) < $eps && $dv1 ==1 && $dv2==1 ) || + (abs($v1p-$v3p) < $eps && $dv1 ==1 && $dv3==1 ) || + (abs($v2p-$v3p) < $eps && $dv2 ==1 && $dv3==1 )) ) { + + // This means that the contour line crosses exactly two sides + // and that the values of each vertice is such that only this + // contour line will cross this section. + // We can now be smart. The cotour line will simply divide the + // area in two polygons that we can fill and then return. There is no + // need to recurse. + + // First find out which two sides the contour is crossing + if( abs($v1p-$v2p) < $eps ) { + $p4 = array($x1,$y1,$x1p,$y1p,$x2p,$y2p,$x3,$y3,$x1,$y1); + $color4 = $this->GetColor($v1); + + $p3 = array($x1p,$y1p,$x2,$y2,$x2p,$y2p,$x1p,$y1p); + $color3 = $this->GetColor($v2); + + $p = array($x1p,$y1p,$x2p,$y2p); + $color = $this->GetColor($v1p); + $v = $v1p; + } + elseif( abs($v1p-$v3p) < $eps ) { + $p4 = array($x1p,$y1p,$x2,$y2,$x3,$y3,$x3p,$y3p,$x1p,$y1p); + $color4 = $this->GetColor($v2); + + $p3 = array($x1,$y1,$x1p,$y1p,$x3p,$y3p,$x1,$y1); + $color3 = $this->GetColor($v1); + + $p = array($x1p,$y1p,$x3p,$y3p); + $color = $this->GetColor($v1p); + $v = $v1p; + } + else { + $p4 = array($x1,$y1,$x2,$y2,$x2p,$y2p,$x3p,$y3p,$x1,$y1); + $color4 = $this->GetColor($v2); + + $p3 = array($x3p,$y3p,$x2p,$y2p,$x3,$y3,$x3p,$y3p); + $color3 = $this->GetColor($v3); + + $p = array($x3p,$y3p,$x2p,$y2p); + $color = $this->GetColor($v3p); + $v = $v3p; + } + $this->FillPolygon($color4,$p4); + $this->FillPolygon($color3,$p3); + + if( $this->showcontlines ) { + if( $this->dofill ) { + $this->shape->SetColor($this->contlinecolor); + } + else { + $this->shape->SetColor($color); + } + $this->shape->Line($p[0],$p[1],$p[2],$p[3]); + } + if( $this->showlabels ) { + $this->putLabel( ($p[0]+$p[2])/2, ($p[1]+$p[3])/2, $p[2], $p[3], $v); + } + } + else { + $this->TriFill($v1, $v1p, $v3p, $x1, $y1, $x1p, $y1p, $x3p, $y3p, $depth+1); + $this->TriFill($v1p, $v2, $v2p, $x1p, $y1p, $x2, $y2, $x2p, $y2p, $depth+1); + $this->TriFill($v3p, $v1p, $v2p, $x3p, $y3p, $x1p, $y1p, $x2p, $y2p, $depth+1); + $this->TriFill($v3p, $v2p, $v3, $x3p, $y3p, $x2p, $y2p, $x3, $y3, $depth+1); + } + } + } + } + + function Fill($v1,$v2,$v3,$maxdepth) { + $x1=0; $y1=1; + $x2=1; $y2=0; + $x3=1; $y3=1; + self::$maxdepth = $maxdepth; + $this->TriFill($v1, $v2, $v3, $x1, $y1, $x2, $y2, $x3, $y3, 0); + } + + function Fillmesh($meshdata,$maxdepth,$method='tri') { + $nx = count($meshdata[0]); + $ny = count($meshdata); + self::$maxdepth = $maxdepth; + for( $x=0; $x < $nx-1; ++$x ) { + for( $y=0; $y < $ny-1; ++$y ) { + $v1 = $meshdata[$y][$x]; + $v2 = $meshdata[$y][$x+1]; + $v3 = $meshdata[$y+1][$x+1]; + $v4 = $meshdata[$y+1][$x]; + + if( $method == 'tri' ) { + // Fill upper and lower triangle + $this->TriFill($v4, $v1, $v2, $x, $y+1, $x, $y, $x+1, $y, 0); + $this->TriFill($v4, $v2, $v3, $x, $y+1, $x+1, $y, $x+1, $y+1, 0); + } + else { + $this->RectFill($v4, $v1, $v2, $v3, $x, $y+1, $x, $y, $x+1, $y, $x+1, $y+1, 0); + } + } + } + if( $this->showlabels ) { + $this->strokeLabels(); + } + } +} + +$meshdata = array( + array (12,12,10,10), + array (10,10,8,14), + array (7,7,13,17), + array (4,5,8,12), + array (10,8,7,8)); + +$tt = new SingleTestTriangle(400,400,count($meshdata[0])-1,count($meshdata)-1); +$tt->SetContours(array(4.7, 6.0, 7.2, 8.6, 9.9, 11.2, 12.5, 13.8, 15.1, 16.4)); +$tt->SetFilled(true); + +//$tt->ShowTriangulation(true); +$tt->ShowLines(true); + +//$tt->ShowLabels(true); +$tt->Fillmesh($meshdata, 8, 'rect'); + +//$tt->Fill(4.0,3.0,7.0, 4); +//$tt->Fill(7,4,1,5); +//$tt->Fill(1,7,4,5); + +$tt->Stroke(); + +?> diff --git a/ext/jpgraph-3.0.7/src/flag_mapping b/ext/jpgraph-3.0.7/src/flag_mapping index 7f9c3c5..b86a9f6 100644 --- a/ext/jpgraph-3.0.7/src/flag_mapping +++ b/ext/jpgraph-3.0.7/src/flag_mapping @@ -1,237 +1,237 @@ -class JpCountryFlags { - -$iCountryFlags = array( - 'Afghanistan' => 'afgh.gif', - 'Republic of Angola' => 'agla.gif', - 'Republic of Albania' => 'alba.gif', - 'Alderney' => 'alde.gif', - 'Democratic and Popular Republic of Algeria' => 'alge.gif', - 'Territory of American Samoa' => 'amsa.gif', - 'Principality of Andorra' => 'andr.gif', - 'British Overseas Territory of Anguilla' => 'angu.gif', - 'Antarctica' => 'anta.gif', - 'Argentine Republic' => 'arge.gif', - 'League of Arab States' => 'arle.gif', - 'Republic of Armenia' => 'arme.gif', - 'Aruba' => 'arub.gif', - 'Commonwealth of Australia' => 'astl.gif', - 'Republic of Austria' => 'aust.gif', - 'Azerbaijani Republic' => 'azer.gif', - 'British Antarctic Territory' => 'bant.gif', - 'Kingdom of Belgium' => 'belg.gif', - 'British Overseas Territory of Bermuda' => 'berm.gif', - 'Commonwealth of the Bahamas' => 'bhms.gif', - 'Kingdom of Bahrain' => 'bhrn.gif', - 'Republic of Belarus' => 'blru.gif', - 'Republic of Bolivia' => 'blva.gif', - 'Belize' => 'blze.gif', - 'Republic of Benin' => 'bnin.gif', - 'Republic of Botswana' => 'bots.gif', - 'Federative Republic of Brazil' => 'braz.gif', - 'Barbados' => 'brbd.gif', - 'British Indian Ocean Territory' => 'brin.gif', - 'Brunei Darussalam' => 'brun.gif', - 'Republic of Burkina' => 'bufa.gif', - 'Republic of Bulgaria' => 'bulg.gif', - 'Republic of Burundi' => 'buru.gif', - 'Overseas Territory of the British Virgin Islands' => 'bvis.gif', - 'Central African Republic' => 'cafr.gif', - 'Kingdom of Cambodia' => 'camb.gif', - 'Republic of Cameroon' => 'came.gif', - 'Dominion of Canada' => 'cana.gif', - 'Caribbean Community' => 'cari.gif', - 'Republic of Cape Verde' => 'cave.gif', - 'Republic of Chad' => 'chad.gif', - 'Republic of Chile' => 'chil.gif', - 'Territory of Christmas Island' => 'chms.gif', - 'Commonwealth of Independent States' => 'cins.gif', - 'Cook Islands' => 'ckis.gif', - 'Republic of Colombia' => 'clmb.gif', - 'Territory of Cocos Islands' => 'cois.gif', - 'Commonwealth' => 'comn.gif', - 'Union of the Comoros' => 'como.gif', - 'Republic of the Congo' => 'cong.gif', - 'Republic of Costa Rica' => 'corc.gif', - 'Republic of Croatia' => 'croa.gif', - 'Republic of Cuba' => 'cuba.gif', - 'British Overseas Territory of the Cayman Islands' => 'cyis.gif', - 'Republic of Cyprus' => 'cypr.gif', - 'The Czech Republic' => 'czec.gif', - 'Kingdom of Denmark' => 'denm.gif', - 'Republic of Djibouti' => 'djib.gif', - 'Commonwealth of Dominica' => 'domn.gif', - 'Dominican Republic' => 'dore.gif', - 'Republic of Ecuador' => 'ecua.gif', - 'Arab Republic of Egypt' => 'egyp.gif', - 'Republic of El Salvador' => 'elsa.gif', - 'England' => 'engl.gif', - 'Republic of Equatorial Guinea' => 'eqgu.gif', - 'State of Eritrea' => 'erit.gif', - 'Republic of Estonia' => 'estn.gif', - 'Ethiopia' => 'ethp.gif', - 'European Union' => 'euun.gif', - 'British Overseas Territory of the Falkland Islands' => 'fais.gif', - 'International Federation of Vexillological Associations' => 'fiav.gif', - 'Republic of Fiji' => 'fiji.gif', - 'Republic of Finland' => 'finl.gif', - 'Territory of French Polynesia' => 'fpol.gif', - 'French Republic' => 'fran.gif', - 'Overseas Department of French Guiana' => 'frgu.gif', - 'Gabonese Republic' => 'gabn.gif', - 'Republic of the Gambia' => 'gamb.gif', - 'Republic of Georgia' => 'geor.gif', - 'Federal Republic of Germany' => 'germ.gif', - 'Republic of Ghana' => 'ghan.gif', - 'Gibraltar' => 'gibr.gif', - 'Hellenic Republic' => 'grec.gif', - 'State of Grenada' => 'gren.gif', - 'Overseas Department of Guadeloupe' => 'guad.gif', - 'Territory of Guam' => 'guam.gif', - 'Republic of Guatemala' => 'guat.gif', - 'The Bailiwick of Guernsey' => 'guer.gif', - 'Republic of Guinea' => 'guin.gif', - 'Republic of Haiti' => 'hait.gif', - 'Hong Kong Special Administrative Region' => 'hokn.gif', - 'Republic of Honduras' => 'hond.gif', - 'Republic of Hungary' => 'hung.gif', - 'Republic of Iceland' => 'icel.gif', - 'International Committee of the Red Cross' => 'icrc.gif', - 'Republic of India' => 'inda.gif', - 'Republic of Indonesia' => 'indn.gif', - 'Republic of Iraq' => 'iraq.gif', - 'Republic of Ireland' => 'irel.gif', - 'Organization of the Islamic Conference' => 'isco.gif', - 'Isle of Man' => 'isma.gif', - 'State of Israel' => 'isra.gif', - 'Italian Republic' => 'ital.gif', - 'Jamaica' => 'jama.gif', - 'Japan' => 'japa.gif', - 'The Bailiwick of Jersey' => 'jers.gif', - 'Hashemite Kingdom of Jordan' => 'jord.gif', - 'Republic of Kazakhstan' => 'kazk.gif', - 'Republic of Kenya' => 'keny.gif', - 'Republic of Kiribati' => 'kirb.gif', - 'State of Kuwait' => 'kuwa.gif', - 'Kyrgyz Republic' => 'kyrg.gif', - 'Republic of Latvia' => 'latv.gif', - 'Lebanese Republic' => 'leba.gif', - 'Kingdom of Lesotho' => 'lest.gif', - 'Republic of Liberia' => 'libe.gif', - 'Principality of Liechtenstein' => 'liec.gif', - 'Republic of Lithuania' => 'lith.gif', - 'Grand Duchy of Luxembourg' => 'luxe.gif', - 'Macao Special Administrative Region' => 'maca.gif', - 'Republic of Macedonia' => 'mace.gif', - 'Republic of Madagascar' => 'mada.gif', - 'Republic of the Marshall Islands' => 'mais.gif', - 'Republic of Maldives' => 'mald.gif', - 'Republic of Mali' => 'mali.gif', - 'Federation of Malaysia' => 'mals018.gif', - 'Republic of Malta' => 'malt.gif', - 'Republic of Malawi' => 'malw.gif', - 'Overseas Department of Martinique' => 'mart.gif', - 'Islamic Republic of Mauritania' => 'maur.gif', - 'Territorial Collectivity of Mayotte' => 'mayt.gif', - 'United Mexican States' => 'mexc.gif', - 'Federated States of Micronesia' => 'micr.gif', - 'Midway Islands' => 'miis.gif', - 'Republic of Moldova' => 'mold.gif', - 'Principality of Monaco' => 'mona.gif', - 'Republic of Mongolia' => 'mong.gif', - 'British Overseas Territory of Montserrat' => 'mont.gif', - 'Kingdom of Morocco' => 'morc.gif', - 'Republic of Mozambique' => 'moza.gif', - 'Republic of Mauritius' => 'mrts.gif', - 'Union of Myanmar' => 'myan.gif', - 'Republic of Namibia' => 'namb.gif', - 'North Atlantic Treaty Organization' => 'nato.gif', - 'Republic of Nauru' => 'naur.gif', - 'Turkish Republic of Northern Cyprus' => 'ncyp.gif', - 'Netherlands Antilles' => 'nean.gif', - 'Kingdom of Nepal' => 'nepa.gif', - 'Kingdom of the Netherlands' => 'neth.gif', - 'Territory of Norfolk Island' => 'nfis.gif', - 'Federal Republic of Nigeria' => 'ngra.gif', - 'Republic of Nicaragua' => 'nica.gif', - 'Republic of Niger' => 'nigr.gif', - 'Niue' => 'niue.gif', - 'Commonwealth of the Northern Mariana Islands' => 'nmar.gif', - 'Province of Northern Ireland' => 'noir.gif', - 'Nordic Council' => 'nord.gif', - 'Kingdom of Norway' => 'norw.gif', - 'Territory of New Caledonia and Dependencies' => 'nwca.gif', - 'New Zealand' => 'nwze.gif', - 'Organization of American States' => 'oast.gif', - 'Organization of African Unity' => 'oaun.gif', - 'International Olympic Committee' => 'olym.gif', - 'Sultanate of Oman' => 'oman.gif', - 'Organization of Petroleum Exporting Countries' => 'opec.gif', - 'Islamic Republic of Pakistan' => 'paks.gif', - 'Republic of Palau' => 'pala.gif', - 'Independent State of Papua New Guinea' => 'pang.gif', - 'Republic of Paraguay' => 'para.gif', - 'Republic of the Philippines' => 'phil.gif', - 'British Overseas Territory of the Pitcairn Islands' => 'piis.gif', - 'Republic of Poland' => 'pola.gif', - 'Republic of Portugal' => 'port.gif', - 'Commonwealth of Puerto Rico' => 'purc.gif', - 'State of Qatar' => 'qata.gif', - 'Russian Federation' => 'russ.gif', - 'Republic of Rwanda' => 'rwan.gif', - 'Kingdom of Saudi Arabia' => 'saar.gif', - 'Republic of San Marino' => 'sama.gif', - 'Nordic Sami Conference' => 'sami.gif', - 'Sark' => 'sark.gif', - 'Scotland' => 'scot.gif', - 'Principality of Seborga' => 'sebo.gif', - 'Republic of Sierra Leone' => 'sile.gif', - 'Republic of Singapore' => 'sing.gif', - 'Republic of Korea' => 'skor.gif', - 'Republic of Slovenia' => 'slva.gif', - 'Somali Republic' => 'smla.gif', - 'Republic of Somaliland' => 'smld.gif', - 'Republic of South Africa' => 'soaf.gif', - 'Solomon Islands' => 'sois.gif', - 'Kingdom of Spain' => 'span.gif', - 'Secretariat of the Pacific Community' => 'spco.gif', - 'Democratic Socialist Republic of Sri Lanka' => 'srla.gif', - 'Saint Lucia' => 'stlu.gif', - 'Republic of the Sudan' => 'suda.gif', - 'Republic of Suriname' => 'surn.gif', - 'Slovak Republic' => 'svka.gif', - 'Kingdom of Sweden' => 'swdn.gif', - 'Swiss Confederation' => 'swit.gif', - 'Syrian Arab Republic' => 'syra.gif', - 'Kingdom of Swaziland' => 'szld.gif', - 'Republic of China' => 'taiw.gif', - 'Republic of Tajikistan' => 'tajk.gif', - 'United Republic of Tanzania' => 'tanz.gif', - 'Kingdom of Thailand' => 'thal.gif', - 'Autonomous Region of Tibet' => 'tibe.gif', - 'Turkmenistan' => 'tkst.gif', - 'Togolese Republic' => 'togo.gif', - 'Tokelau' => 'toke.gif', - 'Kingdom of Tonga' => 'tong.gif', - 'Tristan da Cunha' => 'trdc.gif', - 'Tromelin' => 'tris.gif', - 'Republic of Tunisia' => 'tuns.gif', - 'Republic of Turkey' => 'turk.gif', - 'Tuvalu' => 'tuva.gif', - 'United Arab Emirates' => 'uaem.gif', - 'Republic of Uganda' => 'ugan.gif', - 'Ukraine' => 'ukrn.gif', - 'United Kingdom of Great Britain' => 'unkg.gif', - 'United Nations' => 'unna.gif', - 'United States of America' => 'unst.gif', - 'Oriental Republic of Uruguay' => 'urgy.gif', - 'Virgin Islands of the United States' => 'usvs.gif', - 'Republic of Uzbekistan' => 'uzbk.gif', - 'State of the Vatican City' => 'vacy.gif', - 'Republic of Vanuatu' => 'vant.gif', - 'Bolivarian Republic of Venezuela' => 'venz.gif', - 'Republic of Yemen' => 'yemn.gif', - 'Democratic Republic of Congo' => 'zare.gif', - 'Republic of Zimbabwe' => 'zbwe.gif' -) ; - - +class JpCountryFlags { + +$iCountryFlags = array( + 'Afghanistan' => 'afgh.gif', + 'Republic of Angola' => 'agla.gif', + 'Republic of Albania' => 'alba.gif', + 'Alderney' => 'alde.gif', + 'Democratic and Popular Republic of Algeria' => 'alge.gif', + 'Territory of American Samoa' => 'amsa.gif', + 'Principality of Andorra' => 'andr.gif', + 'British Overseas Territory of Anguilla' => 'angu.gif', + 'Antarctica' => 'anta.gif', + 'Argentine Republic' => 'arge.gif', + 'League of Arab States' => 'arle.gif', + 'Republic of Armenia' => 'arme.gif', + 'Aruba' => 'arub.gif', + 'Commonwealth of Australia' => 'astl.gif', + 'Republic of Austria' => 'aust.gif', + 'Azerbaijani Republic' => 'azer.gif', + 'British Antarctic Territory' => 'bant.gif', + 'Kingdom of Belgium' => 'belg.gif', + 'British Overseas Territory of Bermuda' => 'berm.gif', + 'Commonwealth of the Bahamas' => 'bhms.gif', + 'Kingdom of Bahrain' => 'bhrn.gif', + 'Republic of Belarus' => 'blru.gif', + 'Republic of Bolivia' => 'blva.gif', + 'Belize' => 'blze.gif', + 'Republic of Benin' => 'bnin.gif', + 'Republic of Botswana' => 'bots.gif', + 'Federative Republic of Brazil' => 'braz.gif', + 'Barbados' => 'brbd.gif', + 'British Indian Ocean Territory' => 'brin.gif', + 'Brunei Darussalam' => 'brun.gif', + 'Republic of Burkina' => 'bufa.gif', + 'Republic of Bulgaria' => 'bulg.gif', + 'Republic of Burundi' => 'buru.gif', + 'Overseas Territory of the British Virgin Islands' => 'bvis.gif', + 'Central African Republic' => 'cafr.gif', + 'Kingdom of Cambodia' => 'camb.gif', + 'Republic of Cameroon' => 'came.gif', + 'Dominion of Canada' => 'cana.gif', + 'Caribbean Community' => 'cari.gif', + 'Republic of Cape Verde' => 'cave.gif', + 'Republic of Chad' => 'chad.gif', + 'Republic of Chile' => 'chil.gif', + 'Territory of Christmas Island' => 'chms.gif', + 'Commonwealth of Independent States' => 'cins.gif', + 'Cook Islands' => 'ckis.gif', + 'Republic of Colombia' => 'clmb.gif', + 'Territory of Cocos Islands' => 'cois.gif', + 'Commonwealth' => 'comn.gif', + 'Union of the Comoros' => 'como.gif', + 'Republic of the Congo' => 'cong.gif', + 'Republic of Costa Rica' => 'corc.gif', + 'Republic of Croatia' => 'croa.gif', + 'Republic of Cuba' => 'cuba.gif', + 'British Overseas Territory of the Cayman Islands' => 'cyis.gif', + 'Republic of Cyprus' => 'cypr.gif', + 'The Czech Republic' => 'czec.gif', + 'Kingdom of Denmark' => 'denm.gif', + 'Republic of Djibouti' => 'djib.gif', + 'Commonwealth of Dominica' => 'domn.gif', + 'Dominican Republic' => 'dore.gif', + 'Republic of Ecuador' => 'ecua.gif', + 'Arab Republic of Egypt' => 'egyp.gif', + 'Republic of El Salvador' => 'elsa.gif', + 'England' => 'engl.gif', + 'Republic of Equatorial Guinea' => 'eqgu.gif', + 'State of Eritrea' => 'erit.gif', + 'Republic of Estonia' => 'estn.gif', + 'Ethiopia' => 'ethp.gif', + 'European Union' => 'euun.gif', + 'British Overseas Territory of the Falkland Islands' => 'fais.gif', + 'International Federation of Vexillological Associations' => 'fiav.gif', + 'Republic of Fiji' => 'fiji.gif', + 'Republic of Finland' => 'finl.gif', + 'Territory of French Polynesia' => 'fpol.gif', + 'French Republic' => 'fran.gif', + 'Overseas Department of French Guiana' => 'frgu.gif', + 'Gabonese Republic' => 'gabn.gif', + 'Republic of the Gambia' => 'gamb.gif', + 'Republic of Georgia' => 'geor.gif', + 'Federal Republic of Germany' => 'germ.gif', + 'Republic of Ghana' => 'ghan.gif', + 'Gibraltar' => 'gibr.gif', + 'Hellenic Republic' => 'grec.gif', + 'State of Grenada' => 'gren.gif', + 'Overseas Department of Guadeloupe' => 'guad.gif', + 'Territory of Guam' => 'guam.gif', + 'Republic of Guatemala' => 'guat.gif', + 'The Bailiwick of Guernsey' => 'guer.gif', + 'Republic of Guinea' => 'guin.gif', + 'Republic of Haiti' => 'hait.gif', + 'Hong Kong Special Administrative Region' => 'hokn.gif', + 'Republic of Honduras' => 'hond.gif', + 'Republic of Hungary' => 'hung.gif', + 'Republic of Iceland' => 'icel.gif', + 'International Committee of the Red Cross' => 'icrc.gif', + 'Republic of India' => 'inda.gif', + 'Republic of Indonesia' => 'indn.gif', + 'Republic of Iraq' => 'iraq.gif', + 'Republic of Ireland' => 'irel.gif', + 'Organization of the Islamic Conference' => 'isco.gif', + 'Isle of Man' => 'isma.gif', + 'State of Israel' => 'isra.gif', + 'Italian Republic' => 'ital.gif', + 'Jamaica' => 'jama.gif', + 'Japan' => 'japa.gif', + 'The Bailiwick of Jersey' => 'jers.gif', + 'Hashemite Kingdom of Jordan' => 'jord.gif', + 'Republic of Kazakhstan' => 'kazk.gif', + 'Republic of Kenya' => 'keny.gif', + 'Republic of Kiribati' => 'kirb.gif', + 'State of Kuwait' => 'kuwa.gif', + 'Kyrgyz Republic' => 'kyrg.gif', + 'Republic of Latvia' => 'latv.gif', + 'Lebanese Republic' => 'leba.gif', + 'Kingdom of Lesotho' => 'lest.gif', + 'Republic of Liberia' => 'libe.gif', + 'Principality of Liechtenstein' => 'liec.gif', + 'Republic of Lithuania' => 'lith.gif', + 'Grand Duchy of Luxembourg' => 'luxe.gif', + 'Macao Special Administrative Region' => 'maca.gif', + 'Republic of Macedonia' => 'mace.gif', + 'Republic of Madagascar' => 'mada.gif', + 'Republic of the Marshall Islands' => 'mais.gif', + 'Republic of Maldives' => 'mald.gif', + 'Republic of Mali' => 'mali.gif', + 'Federation of Malaysia' => 'mals018.gif', + 'Republic of Malta' => 'malt.gif', + 'Republic of Malawi' => 'malw.gif', + 'Overseas Department of Martinique' => 'mart.gif', + 'Islamic Republic of Mauritania' => 'maur.gif', + 'Territorial Collectivity of Mayotte' => 'mayt.gif', + 'United Mexican States' => 'mexc.gif', + 'Federated States of Micronesia' => 'micr.gif', + 'Midway Islands' => 'miis.gif', + 'Republic of Moldova' => 'mold.gif', + 'Principality of Monaco' => 'mona.gif', + 'Republic of Mongolia' => 'mong.gif', + 'British Overseas Territory of Montserrat' => 'mont.gif', + 'Kingdom of Morocco' => 'morc.gif', + 'Republic of Mozambique' => 'moza.gif', + 'Republic of Mauritius' => 'mrts.gif', + 'Union of Myanmar' => 'myan.gif', + 'Republic of Namibia' => 'namb.gif', + 'North Atlantic Treaty Organization' => 'nato.gif', + 'Republic of Nauru' => 'naur.gif', + 'Turkish Republic of Northern Cyprus' => 'ncyp.gif', + 'Netherlands Antilles' => 'nean.gif', + 'Kingdom of Nepal' => 'nepa.gif', + 'Kingdom of the Netherlands' => 'neth.gif', + 'Territory of Norfolk Island' => 'nfis.gif', + 'Federal Republic of Nigeria' => 'ngra.gif', + 'Republic of Nicaragua' => 'nica.gif', + 'Republic of Niger' => 'nigr.gif', + 'Niue' => 'niue.gif', + 'Commonwealth of the Northern Mariana Islands' => 'nmar.gif', + 'Province of Northern Ireland' => 'noir.gif', + 'Nordic Council' => 'nord.gif', + 'Kingdom of Norway' => 'norw.gif', + 'Territory of New Caledonia and Dependencies' => 'nwca.gif', + 'New Zealand' => 'nwze.gif', + 'Organization of American States' => 'oast.gif', + 'Organization of African Unity' => 'oaun.gif', + 'International Olympic Committee' => 'olym.gif', + 'Sultanate of Oman' => 'oman.gif', + 'Organization of Petroleum Exporting Countries' => 'opec.gif', + 'Islamic Republic of Pakistan' => 'paks.gif', + 'Republic of Palau' => 'pala.gif', + 'Independent State of Papua New Guinea' => 'pang.gif', + 'Republic of Paraguay' => 'para.gif', + 'Republic of the Philippines' => 'phil.gif', + 'British Overseas Territory of the Pitcairn Islands' => 'piis.gif', + 'Republic of Poland' => 'pola.gif', + 'Republic of Portugal' => 'port.gif', + 'Commonwealth of Puerto Rico' => 'purc.gif', + 'State of Qatar' => 'qata.gif', + 'Russian Federation' => 'russ.gif', + 'Republic of Rwanda' => 'rwan.gif', + 'Kingdom of Saudi Arabia' => 'saar.gif', + 'Republic of San Marino' => 'sama.gif', + 'Nordic Sami Conference' => 'sami.gif', + 'Sark' => 'sark.gif', + 'Scotland' => 'scot.gif', + 'Principality of Seborga' => 'sebo.gif', + 'Republic of Sierra Leone' => 'sile.gif', + 'Republic of Singapore' => 'sing.gif', + 'Republic of Korea' => 'skor.gif', + 'Republic of Slovenia' => 'slva.gif', + 'Somali Republic' => 'smla.gif', + 'Republic of Somaliland' => 'smld.gif', + 'Republic of South Africa' => 'soaf.gif', + 'Solomon Islands' => 'sois.gif', + 'Kingdom of Spain' => 'span.gif', + 'Secretariat of the Pacific Community' => 'spco.gif', + 'Democratic Socialist Republic of Sri Lanka' => 'srla.gif', + 'Saint Lucia' => 'stlu.gif', + 'Republic of the Sudan' => 'suda.gif', + 'Republic of Suriname' => 'surn.gif', + 'Slovak Republic' => 'svka.gif', + 'Kingdom of Sweden' => 'swdn.gif', + 'Swiss Confederation' => 'swit.gif', + 'Syrian Arab Republic' => 'syra.gif', + 'Kingdom of Swaziland' => 'szld.gif', + 'Republic of China' => 'taiw.gif', + 'Republic of Tajikistan' => 'tajk.gif', + 'United Republic of Tanzania' => 'tanz.gif', + 'Kingdom of Thailand' => 'thal.gif', + 'Autonomous Region of Tibet' => 'tibe.gif', + 'Turkmenistan' => 'tkst.gif', + 'Togolese Republic' => 'togo.gif', + 'Tokelau' => 'toke.gif', + 'Kingdom of Tonga' => 'tong.gif', + 'Tristan da Cunha' => 'trdc.gif', + 'Tromelin' => 'tris.gif', + 'Republic of Tunisia' => 'tuns.gif', + 'Republic of Turkey' => 'turk.gif', + 'Tuvalu' => 'tuva.gif', + 'United Arab Emirates' => 'uaem.gif', + 'Republic of Uganda' => 'ugan.gif', + 'Ukraine' => 'ukrn.gif', + 'United Kingdom of Great Britain' => 'unkg.gif', + 'United Nations' => 'unna.gif', + 'United States of America' => 'unst.gif', + 'Oriental Republic of Uruguay' => 'urgy.gif', + 'Virgin Islands of the United States' => 'usvs.gif', + 'Republic of Uzbekistan' => 'uzbk.gif', + 'State of the Vatican City' => 'vacy.gif', + 'Republic of Vanuatu' => 'vant.gif', + 'Bolivarian Republic of Venezuela' => 'venz.gif', + 'Republic of Yemen' => 'yemn.gif', + 'Democratic Republic of Congo' => 'zare.gif', + 'Republic of Zimbabwe' => 'zbwe.gif' +) ; + + diff --git a/ext/jpgraph-3.0.7/src/gd_image.inc.php b/ext/jpgraph-3.0.7/src/gd_image.inc.php index 9eda8df..558dcab 100644 --- a/ext/jpgraph-3.0.7/src/gd_image.inc.php +++ b/ext/jpgraph-3.0.7/src/gd_image.inc.php @@ -1,2021 +1,2021 @@ -CreateImgCanvas($aWidth,$aHeight); - - if( $aSetAutoMargin ) { - $this->SetAutoMargin(); - } - - if( !$this->SetImgFormat($aFormat) ) { - JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); - } - $this->ttf = new TTF(); - $this->langconv = new LanguageConv(); - } - - // Enable interlacing in images - function SetInterlace($aFlg=true) { - $this->iInterlace=$aFlg; - } - - // Should we use anti-aliasing. Note: This really slows down graphics! - function SetAntiAliasing($aFlg=true) { - $this->use_anti_aliasing = $aFlg; - if( function_exists('imageantialias') ) { - imageantialias($this->img,$aFlg); - } - else { - JpGraphError::RaiseL(25128);//('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.') - } - } - - function GetAntiAliasing() { - return $this->use_anti_aliasing ; - } - - function CreateRawCanvas($aWidth=0,$aHeight=0) { - if( $aWidth <= 1 || $aHeight <= 1 ) { - JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); - } - - $this->img = @imagecreatetruecolor($aWidth, $aHeight); - if( $this->img < 1 ) { - JpGraphError::RaiseL(25126); - //die("Can't create truecolor image. Check that you really have GD2 library installed."); - } - $this->SetAlphaBlending(); - - if( $this->iInterlace ) { - imageinterlace($this->img,1); - } - if( $this->rgb != null ) { - $this->rgb->img = $this->img ; - } - else { - $this->rgb = new RGB($this->img); - } - } - - function CloneCanvasH() { - $oldimage = $this->img; - $this->CreateRawCanvas($this->width,$this->height); - imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height); - return $oldimage; - } - - function CreateImgCanvas($aWidth=0,$aHeight=0) { - - $old = array($this->img,$this->width,$this->height); - - $aWidth = round($aWidth); - $aHeight = round($aHeight); - - $this->width=$aWidth; - $this->height=$aHeight; - - - if( $aWidth==0 || $aHeight==0 ) { - // We will set the final size later. - // Note: The size must be specified before any other - // img routines that stroke anything are called. - $this->img = null; - $this->rgb = null; - return $old; - } - - $this->CreateRawCanvas($aWidth,$aHeight); - // Set canvas color (will also be the background color for a - // a pallett image - $this->SetColor($this->canvascolor); - $this->FilledRectangle(0,0,$aWidth-1,$aHeight-1); - - return $old ; - } - - function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) { - if( $aw === -1 ) { - $aw = $aWidth; - $ah = $aHeight; - $f = 'imagecopyresized'; - } - else { - $f = 'imagecopyresampled'; - } - $f($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah); - } - - function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) { - $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); - } - - function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { - if( $aMix == 100 ) { - $this->CopyCanvasH($this->img,$fromImg, - $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); - } - else { - if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) { - // Create a new canvas that will hold the re-scaled original from image - if( $toWidth <= 1 || $toHeight <= 1 ) { - JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.'); - } - - $tmpimg = @imagecreatetruecolor($toWidth, $toHeight); - - if( $tmpimg < 1 ) { - JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?'); - } - $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0, - $toWidth,$toHeight,$fromWidth,$fromHeight); - $fromImg = $tmpimg; - } - imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix); - } - } - - static function GetWidth($aImg=null) { - if( $aImg === null ) { - $aImg = $this->img; - } - return imagesx($aImg); - } - - static function GetHeight($aImg=null) { - if( $aImg === null ) { - $aImg = $this->img; - } - return imagesy($aImg); - } - - static function CreateFromString($aStr) { - $img = imagecreatefromstring($aStr); - if( $img === false ) { - JpGraphError::RaiseL(25085); - //('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.'); - } - return $img; - } - - function SetCanvasH($aHdl) { - $this->img = $aHdl; - $this->rgb->img = $aHdl; - } - - function SetCanvasColor($aColor) { - $this->canvascolor = $aColor ; - } - - function SetAlphaBlending($aFlg=true) { - ImageAlphaBlending($this->img,$aFlg); - } - - function SetAutoMargin() { - $min_bm=5; - $lm = min(40,$this->width/7); - $rm = min(20,$this->width/10); - $tm = max(5,$this->height/7); - $bm = max($min_bm,$this->height/6); - $this->SetMargin($lm,$rm,$tm,$bm); - } - - //--------------- - // PUBLIC METHODS - - function SetFont($family,$style=FS_NORMAL,$size=10) { - $this->font_family=$family; - $this->font_style=$style; - $this->font_size=$size; - $this->font_file=''; - if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ - ++$this->font_family; - } - if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file - - // Check that this PHP has support for TTF fonts - if( !function_exists('imagettfbbox') ) { - JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); - } - $this->font_file = $this->ttf->File($this->font_family,$this->font_style); - } - } - - // Get the specific height for a text string - function GetTextHeight($txt="",$angle=0) { - $tmp = preg_split('/\n/',$txt); - $n = count($tmp); - $m=0; - for($i=0; $i< $n; ++$i) { - $m = max($m,strlen($tmp[$i])); - } - - if( $this->font_family <= FF_FONT2+1 ) { - if( $angle==0 ) { - $h = imagefontheight($this->font_family); - if( $h === false ) { - JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); - } - - return $n*$h; - } - else { - $w = @imagefontwidth($this->font_family); - if( $w === false ) { - JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); - } - - return $m*$w; - } - } - else { - $bbox = $this->GetTTFBBox($txt,$angle); - return $bbox[1]-$bbox[5]+1; - } - } - - // Estimate font height - function GetFontHeight($angle=0) { - $txt = "XOMg"; - return $this->GetTextHeight($txt,$angle); - } - - // Approximate font width with width of letter "O" - function GetFontWidth($angle=0) { - $txt = 'O'; - return $this->GetTextWidth($txt,$angle); - } - - // Get actual width of text in absolute pixels. Note that the width is the - // texts projected with onto the x-axis. Call with angle=0 to get the true - // etxt width. - function GetTextWidth($txt,$angle=0) { - - $tmp = preg_split('/\n/',$txt); - $n = count($tmp); - if( $this->font_family <= FF_FONT2+1 ) { - - $m=0; - for($i=0; $i < $n; ++$i) { - $l=strlen($tmp[$i]); - if( $l > $m ) { - $m = $l; - } - } - - if( $angle==0 ) { - $w = @imagefontwidth($this->font_family); - if( $w === false ) { - JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); - } - return $m*$w; - } - else { - // 90 degrees internal so height becomes width - $h = @imagefontheight($this->font_family); - if( $h === false ) { - JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.'); - } - return $n*$h; - } - } - else { - // For TTF fonts we must walk through a lines and find the - // widest one which we use as the width of the multi-line - // paragraph - $m=0; - for( $i=0; $i < $n; ++$i ) { - $bbox = $this->GetTTFBBox($tmp[$i],$angle); - $mm = $bbox[2] - $bbox[0]; - if( $mm > $m ) - $m = $mm; - } - return $m; - } - } - - - // Draw text with a box around it - function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", - $shadowcolor=false,$paragraph_align="left", - $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { - - $oldx = $this->lastx; - $oldy = $this->lasty; - - if( !is_numeric($dir) ) { - if( $dir=="h" ) $dir=0; - elseif( $dir=="v" ) $dir=90; - else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); - } - - if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { - $width=$this->GetTextWidth($txt,$dir) ; - $height=$this->GetTextHeight($txt,$dir) ; - } - else { - $width=$this->GetBBoxWidth($txt,$dir) ; - $height=$this->GetBBoxHeight($txt,$dir) ; - } - - $height += 2*$ymarg; - $width += 2*$xmarg; - - if( $this->text_halign=="right" ) $x -= $width; - elseif( $this->text_halign=="center" ) $x -= $width/2; - - if( $this->text_valign=="bottom" ) $y -= $height; - elseif( $this->text_valign=="center" ) $y -= $height/2; - - $olda = $this->SetAngle(0); - - if( $shadowcolor ) { - $this->PushColor($shadowcolor); - $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth, - $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth, - $cornerradius); - $this->PopColor(); - $this->PushColor($fcolor); - $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg, - $x+$width,$y+$height-$ymarg, - $cornerradius); - $this->PopColor(); - $this->PushColor($bcolor); - $this->RoundedRectangle($x-$xmarg,$y-$ymarg, - $x+$width,$y+$height-$ymarg,$cornerradius); - $this->PopColor(); - } - else { - if( $fcolor ) { - $oc=$this->current_color; - $this->SetColor($fcolor); - $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); - $this->current_color=$oc; - } - if( $bcolor ) { - $oc=$this->current_color; - $this->SetColor($bcolor); - $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); - $this->current_color=$oc; - } - } - - $h=$this->text_halign; - $v=$this->text_valign; - $this->SetTextAlign("left","top"); - - $debug=false; - $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug); - - $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg, - $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg); - $this->SetTextAlign($h,$v); - - $this->SetAngle($olda); - $this->lastx = $oldx; - $this->lasty = $oldy; - - return $bb; - } - - // Draw text with a box around it. This time the box will be rotated - // with the text. The previous method will just make a larger enough non-rotated - // box to hold the text inside. - function StrokeBoxedText2($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", - $shadowcolor=false,$paragraph_align="left", - $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { - - // This version of boxed text will stroke a rotated box round the text - // thta will follow the angle of the text. - // This has two implications: - // 1) This methos will only support TTF fonts - // 2) The only two alignment that makes sense are centered or baselined - - if( $this->font_family <= FF_FONT2+1 ) { - JpGraphError::RaiseL(25131);//StrokeBoxedText2() Only support TTF fonts and not built in bitmap fonts - } - - $oldx = $this->lastx; - $oldy = $this->lasty; - $dir = $this->NormAngle($dir); - - if( !is_numeric($dir) ) { - if( $dir=="h" ) $dir=0; - elseif( $dir=="v" ) $dir=90; - else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); - } - - $width=$this->GetTextWidth($txt,0) + 2*$xmarg; - $height=$this->GetTextHeight($txt,0) + 2*$ymarg ; - $rect_width=$this->GetBBoxWidth($txt,$dir) ; - $rect_height=$this->GetBBoxHeight($txt,$dir) ; - - $baseline_offset = $this->bbox_cache[1]-1; - - if( $this->text_halign=="center" ) { - if( $dir >= 0 && $dir <= 90 ) { - - $x -= $rect_width/2; - $x += sin($dir*M_PI/180)*$height; - $y += $rect_height/2; - - } elseif( $dir >= 270 && $dir <= 360 ) { - - $x -= $rect_width/2; - $y -= $rect_height/2; - $y += cos($dir*M_PI/180)*$height; - - } elseif( $dir >= 90 && $dir <= 180 ) { - - $x += $rect_width/2; - $y += $rect_height/2; - $y += cos($dir*M_PI/180)*$height; - - } - else { - // $dir > 180 && $dir < 270 - $x += $rect_width/2; - $x += sin($dir*M_PI/180)*$height; - $y -= $rect_height/2; - } - } - - // Rotate the box around this point - $this->SetCenter($x,$y); - $olda = $this->SetAngle(-$dir); - - // We need to use adjusted coordinats for the box to be able - // to draw the box below the baseline. This cannot be done before since - // the rotating point must be the original x,y since that is arounbf the - // point where the text will rotate and we cannot change this since - // that is where the GD/GreeType will rotate the text - - - // For smaller <14pt font we need to do some additional - // adjustments to make it look good - if( $this->font_size < 14 ) { - $x -= 2; - $y += 2; - } - else { - // $y += $baseline_offset; - } - - if( $shadowcolor ) { - $this->PushColor($shadowcolor); - $this->FilledRectangle($x-$xmarg+$dropwidth,$y+$ymarg+$dropwidth-$height, - $x+$width+$dropwidth,$y+$ymarg+$dropwidth); - //$cornerradius); - $this->PopColor(); - $this->PushColor($fcolor); - $this->FilledRectangle($x-$xmarg, $y+$ymarg-$height, - $x+$width, $y+$ymarg); - //$cornerradius); - $this->PopColor(); - $this->PushColor($bcolor); - $this->Rectangle($x-$xmarg,$y+$ymarg-$height, - $x+$width,$y+$ymarg); - //$cornerradius); - $this->PopColor(); - } - else { - if( $fcolor ) { - $oc=$this->current_color; - $this->SetColor($fcolor); - $this->FilledRectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius); - $this->current_color=$oc; - } - if( $bcolor ) { - $oc=$this->current_color; - $this->SetColor($bcolor); - $this->Rectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius); - $this->current_color=$oc; - } - } - - if( $this->font_size < 14 ) { - $x += 2; - $y -= 2; - } - else { - - // Restore the original y before we stroke the text - // $y -= $baseline_offset; - - } - - $this->SetCenter(0,0); - $this->SetAngle($olda); - - $h=$this->text_halign; - $v=$this->text_valign; - if( $this->text_halign == 'center') { - $this->SetTextAlign('center','basepoint'); - } - else { - $this->SetTextAlign('basepoint','basepoint'); - } - - $debug=false; - $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug); - - $bb = array($x-$xmarg, $y+$height-$ymarg, - $x+$width, $y+$height-$ymarg, - $x+$width, $y-$ymarg, - $x-$xmarg, $y-$ymarg); - - $this->SetTextAlign($h,$v); - $this->SetAngle($olda); - - $this->lastx = $oldx; - $this->lasty = $oldy; - - return $bb; - } - - // Set text alignment - function SetTextAlign($halign,$valign="bottom") { - $this->text_halign=$halign; - $this->text_valign=$valign; - } - - function _StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$aDebug=false) { - - if( is_numeric($dir) && $dir!=90 && $dir!=0) - JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); - - $h=$this->GetTextHeight($txt); - $fh=$this->GetFontHeight(); - $w=$this->GetTextWidth($txt); - - if( $this->text_halign=="right") { - $x -= $dir==0 ? $w : $h; - } - elseif( $this->text_halign=="center" ) { - // For center we subtract 1 pixel since this makes the middle - // be prefectly in the middle - $x -= $dir==0 ? $w/2-1 : $h/2; - } - if( $this->text_valign=="top" ) { - $y += $dir==0 ? $h : $w; - } - elseif( $this->text_valign=="center" ) { - $y += $dir==0 ? $h/2 : $w/2; - } - - if( $dir==90 ) { - imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); - $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); - if( $aDebug ) { - // Draw bounding box - $this->PushColor('green'); - $this->Polygon($aBoundingBox,true); - $this->PopColor(); - } - } - else { - if( preg_match('/\n/',$txt) ) { - $tmp = preg_split('/\n/',$txt); - for($i=0; $i < count($tmp); ++$i) { - $w1 = $this->GetTextWidth($tmp[$i]); - if( $paragraph_align=="left" ) { - imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); - } - elseif( $paragraph_align=="right" ) { - imagestring($this->img,$this->font_family,$x+($w-$w1),$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); - } - else { - imagestring($this->img,$this->font_family,$x+$w/2-$w1/2,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); - } - } - } - else { - //Put the text - imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); - } - if( $aDebug ) { - // Draw the bounding rectangle and the bounding box - $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); - - // Draw bounding box - $this->PushColor('green'); - $this->Polygon($p1,true); - $this->PopColor(); - - } - $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); - } - } - - function AddTxtCR($aTxt) { - // If the user has just specified a '\n' - // instead of '\n\t' we have to add '\r' since - // the width will be too muchy otherwise since when - // we print we stroke the individually lines by hand. - $e = explode("\n",$aTxt); - $n = count($e); - for($i=0; $i<$n; ++$i) { - $e[$i]=str_replace("\r","",$e[$i]); - } - return implode("\n\r",$e); - } - - function NormAngle($a) { - // Normalize angle in degrees - // Normalize angle to be between 0-360 - while( $a > 360 ) - $a -= 360; - while( $a < -360 ) - $a += 360; - if( $a < 0 ) - $a = 360 + $a; - return $a; - } - - function imagettfbbox_fixed($size, $angle, $fontfile, $text) { - - - if( ! USE_LIBRARY_IMAGETTFBBOX ) { - - $bbox = @imagettfbbox($size, $angle, $fontfile, $text); - if( $bbox === false ) { - JpGraphError::RaiseL(25092,$this->font_file); - //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); - } - $this->bbox_cache = $bbox; - return $bbox; - } - - // The built in imagettfbbox is buggy for angles != 0 so - // we calculate this manually by getting the bounding box at - // angle = 0 and then rotate the bounding box manually - $bbox = @imagettfbbox($size, 0, $fontfile, $text); - if( $bbox === false ) { - JpGraphError::RaiseL(25092,$this->font_file); - //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); - } - - $angle = $this->NormAngle($angle); - - $a = $angle*M_PI/180; - $ca = cos($a); - $sa = sin($a); - $ret = array(); - - // We always add 1 pixel to the left since the left edge of the bounding - // box is sometimes coinciding with the first pixel of the text - //$bbox[0] -= 1; - //$bbox[6] -= 1; - - // For roatated text we need to add extra width for rotated - // text since the kerning and stroking of the TTF is not the same as for - // text at a 0 degree angle - - if( $angle > 0.001 && abs($angle-360) > 0.001 ) { - $h = abs($bbox[7]-$bbox[1]); - $w = abs($bbox[2]-$bbox[0]); - - $bbox[0] -= 2; - $bbox[6] -= 2; - // The width is underestimated so compensate for that - $bbox[2] += round($w*0.06); - $bbox[4] += round($w*0.06); - - // and we also need to compensate with increased height - $bbox[5] -= round($h*0.1); - $bbox[7] -= round($h*0.1); - - if( $angle > 90 ) { - // For angles > 90 we also need to extend the height further down - // by the baseline since that is also one more problem - $bbox[1] += round($h*0.15); - $bbox[3] += round($h*0.15); - - // and also make it slighty less height - $bbox[7] += round($h*0.05); - $bbox[5] += round($h*0.05); - - // And we need to move the box slightly top the rright (from a tetx perspective) - $bbox[0] += round($w*0.02); - $bbox[6] += round($w*0.02); - - if( $angle > 180 ) { - // And we need to move the box slightly to the left (from a text perspective) - $bbox[0] -= round($w*0.02); - $bbox[6] -= round($w*0.02); - $bbox[2] -= round($w*0.02); - $bbox[4] -= round($w*0.02); - - } - - } - for($i = 0; $i < 7; $i += 2) { - $ret[$i] = round($bbox[$i] * $ca + $bbox[$i+1] * $sa); - $ret[$i+1] = round($bbox[$i+1] * $ca - $bbox[$i] * $sa); - } - $this->bbox_cache = $ret; - return $ret; - } - else { - $this->bbox_cache = $bbox; - return $bbox; - } - } - - // Deprecated - function GetTTFBBox($aTxt,$aAngle=0) { - $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt); - return $bbox; - } - - function GetBBoxTTF($aTxt,$aAngle=0) { - // Normalize the bounding box to become a minimum - // enscribing rectangle - - $aTxt = $this->AddTxtCR($aTxt); - - if( !is_readable($this->font_file) ) { - JpGraphError::RaiseL(25093,$this->font_file); - //('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.'); - } - $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt); - - if( $aAngle==0 ) return $bbox; - - if( $aAngle >= 0 ) { - if( $aAngle <= 90 ) { //<=0 - $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], - $bbox[2],$bbox[5],$bbox[6],$bbox[5]); - } - elseif( $aAngle <= 180 ) { //<= 2 - $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7], - $bbox[0],$bbox[3],$bbox[4],$bbox[3]); - } - elseif( $aAngle <= 270 ) { //<= 3 - $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], - $bbox[6],$bbox[1],$bbox[2],$bbox[1]); - } - else { - $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], - $bbox[4],$bbox[7],$bbox[0],$bbox[7]); - } - } - elseif( $aAngle < 0 ) { - if( $aAngle <= -270 ) { // <= -3 - $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], - $bbox[2],$bbox[5],$bbox[6],$bbox[5]); - } - elseif( $aAngle <= -180 ) { // <= -2 - $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], - $bbox[4],$bbox[7],$bbox[0],$bbox[7]); - } - elseif( $aAngle <= -90 ) { // <= -1 - $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], - $bbox[6],$bbox[1],$bbox[2],$bbox[1]); - } - else { - $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], - $bbox[4],$bbox[7],$bbox[0],$bbox[7]); - } - } - return $bbox; - } - - function GetBBoxHeight($aTxt,$aAngle=0) { - $box = $this->GetBBoxTTF($aTxt,$aAngle); - return abs($box[7]-$box[1]); - } - - function GetBBoxWidth($aTxt,$aAngle=0) { - $box = $this->GetBBoxTTF($aTxt,$aAngle); - return $box[2]-$box[0]+1; - } - - - function _StrokeTTF($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$debug=false) { - - // Setup default inter line margin for paragraphs to be - // 3% of the font height. - $ConstLineSpacing = 0.03 ; - - // Remember the anchor point before adjustment - if( $debug ) { - $ox=$x; - $oy=$y; - } - - if( !preg_match('/\n/',$txt) || ($dir>0 && preg_match('/\n/',$txt)) ) { - // Format a single line - - $txt = $this->AddTxtCR($txt); - $bbox=$this->GetBBoxTTF($txt,$dir); - $width = $this->GetBBoxWidth($txt,$dir); - $height = $this->GetBBoxHeight($txt,$dir); - - // The special alignment "basepoint" is mostly used internally - // in the library. This will put the anchor position at the left - // basepoint of the tetx. This is the default anchor point for - // TTF text. - - if( $this->text_valign != 'basepoint' ) { - // Align x,y ot lower left corner of bbox - - - if( $this->text_halign=='right' ) { - $x -= $width; - $x -= $bbox[0]; - } - elseif( $this->text_halign=='center' ) { - $x -= $width/2; - $x -= $bbox[0]; - } - elseif( $this->text_halign=='baseline' ) { - // This is only support for text at 90 degree !! - // Do nothing the text is drawn at baseline by default - } - - if( $this->text_valign=='top' ) { - $y -= $bbox[1]; // Adjust to bottom of text - $y += $height; - } - elseif( $this->text_valign=='center' ) { - $y -= $bbox[1]; // Adjust to bottom of text - $y += $height/2; - } - elseif( $this->text_valign=='baseline' ) { - // This is only support for text at 0 degree !! - // Do nothing the text is drawn at baseline by default - } - } - ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, - $this->current_color,$this->font_file,$txt); - - // Calculate and return the co-ordinates for the bounding box - $box = $this->imagettfbbox_fixed($this->font_size,$dir,$this->font_file,$txt); - $p1 = array(); - - for($i=0; $i < 4; ++$i) { - $p1[] = round($box[$i*2]+$x); - $p1[] = round($box[$i*2+1]+$y); - } - $aBoundingBox = $p1; - - // Debugging code to highlight the bonding box and bounding rectangle - // For text at 0 degrees the bounding box and bounding rectangle are the - // same - if( $debug ) { - // Draw the bounding rectangle and the bounding box - - $p = array(); - $p1 = array(); - - for($i=0; $i < 4; ++$i) { - $p[] = $bbox[$i*2]+$x ; - $p[] = $bbox[$i*2+1]+$y; - $p1[] = $box[$i*2]+$x ; - $p1[] = $box[$i*2+1]+$y ; - } - - // Draw bounding box - $this->PushColor('green'); - $this->Polygon($p1,true); - $this->PopColor(); - - // Draw bounding rectangle - $this->PushColor('darkgreen'); - $this->Polygon($p,true); - $this->PopColor(); - - // Draw a cross at the anchor point - $this->PushColor('red'); - $this->Line($ox-15,$oy,$ox+15,$oy); - $this->Line($ox,$oy-15,$ox,$oy+15); - $this->PopColor(); - } - } - else { - // Format a text paragraph - $fh=$this->GetFontHeight(); - - // Line margin is 25% of font height - $linemargin=round($fh*$ConstLineSpacing); - $fh += $linemargin; - $w=$this->GetTextWidth($txt); - - $y -= $linemargin/2; - $tmp = preg_split('/\n/',$txt); - $nl = count($tmp); - $h = $nl * $fh; - - if( $this->text_halign=='right') { - $x -= $dir==0 ? $w : $h; - } - elseif( $this->text_halign=='center' ) { - $x -= $dir==0 ? $w/2 : $h/2; - } - - if( $this->text_valign=='top' ) { - $y += $dir==0 ? $h : $w; - } - elseif( $this->text_valign=='center' ) { - $y += $dir==0 ? $h/2 : $w/2; - } - - // Here comes a tricky bit. - // Since we have to give the position for the string at the - // baseline this means thaht text will move slightly up - // and down depending on any of it's character descend below - // the baseline, for example a 'g'. To adjust the Y-position - // we therefore adjust the text with the baseline Y-offset - // as used for the current font and size. This will keep the - // baseline at a fixed positoned disregarding the actual - // characters in the string. - $standardbox = $this->GetTTFBBox('Gg',$dir); - $yadj = $standardbox[1]; - $xadj = $standardbox[0]; - $aBoundingBox = array(); - for($i=0; $i < $nl; ++$i) { - $wl = $this->GetTextWidth($tmp[$i]); - $bbox = $this->GetTTFBBox($tmp[$i],$dir); - if( $paragraph_align=='left' ) { - $xl = $x; - } - elseif( $paragraph_align=='right' ) { - $xl = $x + ($w-$wl); - } - else { - // Center - $xl = $x + $w/2 - $wl/2 ; - } - - // In theory we should adjust with full pre-lead to get the lines - // lined up but this doesn't look good so therfore we only adjust with - // half th pre-lead - $xl -= $bbox[0]/2; - $yl = $y - $yadj; - //$xl = $xl- $xadj; - ImageTTFText($this->img, $this->font_size, $dir, $xl, $yl-($h-$fh)+$fh*$i, - $this->current_color,$this->font_file,$tmp[$i]); - - // echo "xl=$xl,".$tmp[$i]."
      "; - if( $debug ) { - // Draw the bounding rectangle around each line - $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]); - $p = array(); - for($j=0; $j < 4; ++$j) { - $p[] = $bbox[$j*2]+$xl; - $p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i; - } - - // Draw bounding rectangle - $this->PushColor('darkgreen'); - $this->Polygon($p,true); - $this->PopColor(); - } - } - - // Get the bounding box - $bbox = $this->GetBBoxTTF($txt,$dir); - for($j=0; $j < 4; ++$j) { - $bbox[$j*2]+= round($x); - $bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj); - } - $aBoundingBox = $bbox; - - if( $debug ) { - // Draw a cross at the anchor point - $this->PushColor('red'); - $this->Line($ox-25,$oy,$ox+25,$oy); - $this->Line($ox,$oy-25,$ox,$oy+25); - $this->PopColor(); - } - - } - } - - function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { - - $x = round($x); - $y = round($y); - - // Do special language encoding - $txt = $this->langconv->Convert($txt,$this->font_family); - - if( !is_numeric($dir) ) { - JpGraphError::RaiseL(25094);//(" Direction for text most be given as an angle between 0 and 90."); - } - - if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { - $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); - } - elseif( $this->font_family >= _FIRST_FONT && $this->font_family <= _LAST_FONT) { - $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); - } - else { - JpGraphError::RaiseL(25095);//(" Unknown font font family specification. "); - } - return $boundingbox; - } - - function SetMargin($lm,$rm,$tm,$bm) { - $this->left_margin=$lm; - $this->right_margin=$rm; - $this->top_margin=$tm; - $this->bottom_margin=$bm; - $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; - $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; - if( $this->width > 0 && $this->height > 0 ) { - if( $this->plotwidth < 0 || $this->plotheight < 0 ) { - JpGraphError::RaiseL(25130, $this->plotwidth, $this->plotheight); - //JpGraphError::raise("To small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins."); - } - } - } - - function SetTransparent($color) { - imagecolortransparent ($this->img,$this->rgb->allocate($color)); - } - - function SetColor($color,$aAlpha=0) { - $this->current_color_name = $color; - $this->current_color=$this->rgb->allocate($color,$aAlpha); - if( $this->current_color == -1 ) { - $tc=imagecolorstotal($this->img); - JpGraphError::RaiseL(25096); - //("Can't allocate any more colors. Image has already allocated maximum of $tc colors. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\"USE_APPROX_COLORS\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); - } - return $this->current_color; - } - - function PushColor($color) { - if( $color != "" ) { - $this->colorstack[$this->colorstackidx]=$this->current_color_name; - $this->colorstack[$this->colorstackidx+1]=$this->current_color; - $this->colorstackidx+=2; - $this->SetColor($color); - } - else { - JpGraphError::RaiseL(25097);//("Color specified as empty string in PushColor()."); - } - } - - function PopColor() { - if( $this->colorstackidx < 1 ) { - JpGraphError::RaiseL(25098);//(" Negative Color stack index. Unmatched call to PopColor()"); - } - $this->current_color=$this->colorstack[--$this->colorstackidx]; - $this->current_color_name=$this->colorstack[--$this->colorstackidx]; - } - - - function SetLineWeight($weight) { - $old = $this->line_weight; - imagesetthickness($this->img,$weight); - $this->line_weight = $weight; - return $old; - } - - function SetStartPoint($x,$y) { - $this->lastx=round($x); - $this->lasty=round($y); - } - - function Arc($cx,$cy,$w,$h,$s,$e) { - // GD Arc doesn't like negative angles - while( $s < 0) $s += 360; - while( $e < 0) $e += 360; - imagearc($this->img,round($cx),round($cy),round($w),round($h),$s,$e,$this->current_color); - } - - function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { - $s = round($s); - $e = round($e); - while( $s < 0 ) $s += 360; - while( $e < 0 ) $e += 360; - if( $style=='' ) - $style=IMG_ARC_PIE; - if( abs($s-$e) > 0 ) { - imagefilledarc($this->img,round($xc),round($yc),round($w),round($h),$s,$e,$this->current_color,$style); - } - } - - function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) { - $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name); - } - - function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor="",$arccolor="") { - $s = round($s); $e = round($e); - $w = round($w); $h = round($h); - $xc = round($xc); $yc = round($yc); - if( $s == $e ) { - // A full circle. We draw this a plain circle - $this->PushColor($fillcolor); - imagefilledellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); - - // If antialiasing is used then we often don't have any color no the surrounding - // arc. So, we need to check for this special case so we don't send an empty - // color to the push function. In this case we use the fill color for the arc as well - if( $arccolor != '' ) { - $this->PopColor(); - $this->PushColor($arccolor); - } - imageellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); - $this->Line($xc,$yc,cos($s*M_PI/180)*$w+$xc,$yc+sin($s*M_PI/180)*$h); - $this->PopColor(); - } - else { - $this->PushColor($fillcolor); - $this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e); - $this->PopColor(); - if( $arccolor != "" ) { - $this->PushColor($arccolor); - // We add 2 pixels to make the Arc() better aligned with - // the filled arc. - imagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ; - $this->PopColor(); - } - } - } - - function Ellipse($xc,$yc,$w,$h) { - $this->Arc($xc,$yc,$w,$h,0,360); - } - - function Circle($xc,$yc,$r) { - imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color); - } - - function FilledCircle($xc,$yc,$r) { - imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color); - } - - // Linear Color InterPolation - function lip($f,$t,$p) { - $p = round($p,1); - $r = $f[0] + ($t[0]-$f[0])*$p; - $g = $f[1] + ($t[1]-$f[1])*$p; - $b = $f[2] + ($t[2]-$f[2])*$p; - return array($r,$g,$b); - } - - // Set line style dashed, dotted etc - function SetLineStyle($s) { - if( is_numeric($s) ) { - if( $s<1 || $s>4 ) { - JpGraphError::RaiseL(25101,$s);//(" Illegal numeric argument to SetLineStyle(): ($s)"); - } - } - elseif( is_string($s) ) { - if( $s == "solid" ) $s=1; - elseif( $s == "dotted" ) $s=2; - elseif( $s == "dashed" ) $s=3; - elseif( $s == "longdashed" ) $s=4; - else { - JpGraphError::RaiseL(25102,$s);//(" Illegal string argument to SetLineStyle(): $s"); - } - } - else { - JpGraphError::RaiseL(25103,$s);//(" Illegal argument to SetLineStyle $s"); - } - $old = $this->line_style; - $this->line_style=$s; - return $old; - } - - // Same as Line but take the line_style into account - function StyleLine($x1,$y1,$x2,$y2,$aStyle='') { - if( $this->line_weight <= 0 ) return; - - if( $aStyle === '' ) { - $aStyle = $this->line_style; - } - - // Add error check since dashed line will only work if anti-alias is disabled - // this is a limitation in GD - - if( $aStyle == 1 ) { - // Solid style. We can handle anti-aliasing for this - $this->Line($x1,$y1,$x2,$y2); - } - else { - // Since the GD routines doesn't handle AA for styled line - // we have no option than to turn it off to get any lines at - // all if the weight > 1 - $oldaa = $this->GetAntiAliasing(); - if( $oldaa && $this->line_weight > 1 ) { - $this->SetAntiAliasing(false); - } - - switch( $aStyle ) { - case 2: // Dotted - $this->DashedLine($x1,$y1,$x2,$y2,2,6); - break; - case 3: // Dashed - $this->DashedLine($x1,$y1,$x2,$y2,5,9); - break; - case 4: // Longdashes - $this->DashedLine($x1,$y1,$x2,$y2,9,13); - break; - default: - JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); - break; - } - if( $oldaa ) { - $this->SetAntiAliasing(true); - } - } - } - - function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { - - if( $this->line_weight <= 0 ) return; - - // Add error check to make sure anti-alias is not enabled. - // Dashed line does not work with anti-alias enabled. This - // is a limitation in GD. - if( $this->use_anti_aliasing ) { - JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. - } - - - $x1 = round($x1); - $x2 = round($x2); - $y1 = round($y1); - $y2 = round($y2); - - $style = array_fill(0,$dash_length,$this->current_color); - $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); - imagesetstyle($this->img, $style); - imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); - $this->lastx = $x2; - $this->lasty = $y2; - } - - function Line($x1,$y1,$x2,$y2) { - - if( $this->line_weight <= 0 ) return; - - $x1 = round($x1); - $x2 = round($x2); - $y1 = round($y1); - $y2 = round($y2); - - imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); - $this->lastx=$x2; - $this->lasty=$y2; - } - - function Polygon($p,$closed=FALSE,$fast=FALSE) { - - if( $this->line_weight <= 0 ) return; - - $n=count($p); - $oldx = $p[0]; - $oldy = $p[1]; - if( $fast ) { - for( $i=2; $i < $n; $i+=2 ) { - imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color); - $oldx = $p[$i]; - $oldy = $p[$i+1]; - } - if( $closed ) { - imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color); - } - } - else { - for( $i=2; $i < $n; $i+=2 ) { - $this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]); - $oldx = $p[$i]; - $oldy = $p[$i+1]; - } - if( $closed ) { - $this->StyleLine($oldx,$oldy,$p[0],$p[1]); - } - } - } - - function FilledPolygon($pts) { - $n=count($pts); - if( $n == 0 ) { - JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.'); - } - for($i=0; $i < $n; ++$i) { - $pts[$i] = round($pts[$i]); - } - $old = $this->line_weight; - imagesetthickness($this->img,1); - imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); - $this->line_weight = $old; - imagesetthickness($this->img,$old); - } - - function Rectangle($xl,$yu,$xr,$yl) { - $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu)); - } - - function FilledRectangle($xl,$yu,$xr,$yl) { - $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); - } - - function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) { - // Fill a rectangle with lines of two colors - if( $style===1 ) { - // Horizontal stripe - if( $yl < $yu ) { - $t = $yl; $yl=$yu; $yu=$t; - } - for( $y=$yu; $y <= $yl; ++$y) { - $this->SetColor($color1); - $this->Line($xl,$y,$xr,$y); - ++$y; - $this->SetColor($color2); - $this->Line($xl,$y,$xr,$y); - } - } - else { - if( $xl < $xl ) { - $t = $xl; $xl=$xr; $xr=$t; - } - for( $x=$xl; $x <= $xr; ++$x) { - $this->SetColor($color1); - $this->Line($x,$yu,$x,$yl); - ++$x; - $this->SetColor($color2); - $this->Line($x,$yu,$x,$yl); - } - } - } - - function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=4,$shadow_color='darkgray',$useAlpha=true) { - // This is complicated by the fact that we must also handle the case where - // the reactangle has no fill color - $xl = floor($xl); - $yu = floor($yu); - $xr = floor($xr); - $yl = floor($yl); - $this->PushColor($shadow_color); - $shadowAlpha=0; - $this->SetLineWeight(1); - $this->SetLineStyle('solid'); - $basecolor = $this->rgb->Color($shadow_color); - $shadow_color = array($basecolor[0],$basecolor[1],$basecolor[2],); - for( $i=0; $i < $shadow_width; ++$i ) { - $this->SetColor($shadow_color,$shadowAlpha); - $this->Line($xr-$shadow_width+$i, $yu+$shadow_width, - $xr-$shadow_width+$i, $yl-$shadow_width-1+$i); - $this->Line($xl+$shadow_width, $yl-$shadow_width+$i, - $xr-$shadow_width+$i, $yl-$shadow_width+$i); - if( $useAlpha ) $shadowAlpha += 1.0/$shadow_width; - } - - $this->PopColor(); - if( $fcolor==false ) { - $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); - } - else { - $this->PushColor($fcolor); - $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); - $this->PopColor(); - $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); - } - } - - function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) { - if( $r==0 ) { - $this->FilledRectangle($xt,$yt,$xr,$yl); - return; - } - - // To avoid overlapping fillings (which will look strange - // when alphablending is enabled) we have no choice but - // to fill the five distinct areas one by one. - - // Center square - $this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r); - // Top band - $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r); - // Bottom band - $this->FilledRectangle($xt+$r,$yl-$r,$xr-$r,$yl); - // Left band - $this->FilledRectangle($xt,$yt+$r,$xt+$r,$yl-$r); - // Right band - $this->FilledRectangle($xr-$r,$yt+$r,$xr,$yl-$r); - - // Topleft & Topright arc - $this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270); - $this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360); - - // Bottomleft & Bottom right arc - $this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180); - $this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90); - - } - - function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) { - - if( $r==0 ) { - $this->Rectangle($xt,$yt,$xr,$yl); - return; - } - - // Top & Bottom line - $this->Line($xt+$r,$yt,$xr-$r,$yt); - $this->Line($xt+$r,$yl,$xr-$r,$yl); - - // Left & Right line - $this->Line($xt,$yt+$r,$xt,$yl-$r); - $this->Line($xr,$yt+$r,$xr,$yl-$r); - - // Topleft & Topright arc - $this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); - $this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); - - // Bottomleft & Bottomright arc - $this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); - $this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); - } - - function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') { - $this->FilledRectangle($x1,$y1,$x2,$y2); - $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2); - } - - function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') { - $this->PushColor($color1); - for( $i=0; $i < $depth; ++$i ) { - $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i); - $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i); - } - $this->PopColor(); - - $this->PushColor($color2); - for( $i=0; $i < $depth; ++$i ) { - $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i); - $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1); - } - $this->PopColor(); - } - - function StyleLineTo($x,$y) { - $this->StyleLine($this->lastx,$this->lasty,$x,$y); - $this->lastx=$x; - $this->lasty=$y; - } - - function LineTo($x,$y) { - $this->Line($this->lastx,$this->lasty,$x,$y); - $this->lastx=$x; - $this->lasty=$y; - } - - function Point($x,$y) { - imagesetpixel($this->img,round($x),round($y),$this->current_color); - } - - function Fill($x,$y) { - imagefill($this->img,round($x),round($y),$this->current_color); - } - - function FillToBorder($x,$y,$aBordColor) { - $bc = $this->rgb->allocate($aBordColor); - if( $bc == -1 ) { - JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors'); - } - imagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color); - } - - function SetExpired($aFlg=true) { - $this->expired = $aFlg; - } - - // Generate image header - function Headers() { - - // In case we are running from the command line with the client version of - // PHP we can't send any headers. - $sapi = php_sapi_name(); - if( $sapi == 'cli' ) return; - - // These parameters are set by headers_sent() but they might cause - // an undefined variable error unless they are initilized - $file=''; - $lineno=''; - if( headers_sent($file,$lineno) ) { - $file=basename($file); - $t = new ErrMsgText(); - $msg = $t->Get(10,$file,$lineno); - die($msg); - } - - if ($this->expired) { - header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); - header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); - header("Cache-Control: no-cache, must-revalidate"); - header("Pragma: no-cache"); - } - header("Content-type: image/$this->img_format"); - } - - // Adjust image quality for formats that allow this - function SetQuality($q) { - $this->quality = $q; - } - - // Stream image to browser or to file - function Stream($aFile="") { - $func="image".$this->img_format; - if( $this->img_format=="jpeg" && $this->quality != null ) { - $res = @$func($this->img,$aFile,$this->quality); - } - else { - if( $aFile != "" ) { - $res = @$func($this->img,$aFile); - if( !$res ) { - JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); - } - } - else { - $res = @$func($this->img); - if( !$res ) { - JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); - } - - } - } - } - - // Clear resources used by image (this is normally not used since all resources are/should be - // returned when the script terminates - function Destroy() { - imagedestroy($this->img); - } - - // Specify image format. Note depending on your installation - // of PHP not all formats may be supported. - function SetImgFormat($aFormat,$aQuality=75) { - $this->quality = $aQuality; - $aFormat = strtolower($aFormat); - $tst = true; - $supported = imagetypes(); - if( $aFormat=="auto" ) { - if( $supported & IMG_PNG ) $this->img_format="png"; - elseif( $supported & IMG_JPG ) $this->img_format="jpeg"; - elseif( $supported & IMG_GIF ) $this->img_format="gif"; - elseif( $supported & IMG_WBMP ) $this->img_format="wbmp"; - elseif( $supported & IMG_XPM ) $this->img_format="xpm"; - else { - JpGraphError::RaiseL(25109);//("Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details."); - } - return true; - } - else { - if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { - if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) $tst=false; - elseif( $aFormat=="png" && !($supported & IMG_PNG) ) $tst=false; - elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) $tst=false; - elseif( $aFormat=="wbmp" && !($supported & IMG_WBMP) ) $tst=false; - elseif( $aFormat=="xpm" && !($supported & IMG_XPM) ) $tst=false; - else { - $this->img_format=$aFormat; - return true; - } - } - else { - $tst=false; - } - if( !$tst ) { - JpGraphError::RaiseL(25110,$aFormat);//(" Your PHP installation does not support the chosen graphic format: $aFormat"); - } - } - } -} // CLASS - -//=================================================== -// CLASS RotImage -// Description: Exactly as Image but draws the image at -// a specified angle around a specified rotation point. -//=================================================== -class RotImage extends Image { - public $a=0; - public $dx=0,$dy=0,$transx=0,$transy=0; - private $m=array(); - - function __construct($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { - parent::__construct($aWidth,$aHeight,$aFormat,$aSetAutoMargin); - $this->dx=$this->left_margin+$this->plotwidth/2; - $this->dy=$this->top_margin+$this->plotheight/2; - $this->SetAngle($a); - } - - function SetCenter($dx,$dy) { - $old_dx = $this->dx; - $old_dy = $this->dy; - $this->dx=$dx; - $this->dy=$dy; - $this->SetAngle($this->a); - return array($old_dx,$old_dy); - } - - function SetTranslation($dx,$dy) { - $old = array($this->transx,$this->transy); - $this->transx = $dx; - $this->transy = $dy; - return $old; - } - - function UpdateRotMatrice() { - $a = $this->a; - $a *= M_PI/180; - $sa=sin($a); $ca=cos($a); - // Create the rotation matrix - $this->m[0][0] = $ca; - $this->m[0][1] = -$sa; - $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ; - $this->m[1][0] = $sa; - $this->m[1][1] = $ca; - $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ; - } - - function SetAngle($a) { - $tmp = $this->a; - $this->a = $a; - $this->UpdateRotMatrice(); - return $tmp; - } - - function Circle($xc,$yc,$r) { - list($xc,$yc) = $this->Rotate($xc,$yc); - parent::Circle($xc,$yc,$r); - } - - function FilledCircle($xc,$yc,$r) { - list($xc,$yc) = $this->Rotate($xc,$yc); - parent::FilledCircle($xc,$yc,$r); - } - - - function Arc($xc,$yc,$w,$h,$s,$e) { - list($xc,$yc) = $this->Rotate($xc,$yc); - $s += $this->a; - $e += $this->a; - parent::Arc($xc,$yc,$w,$h,$s,$e); - } - - function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { - list($xc,$yc) = $this->Rotate($xc,$yc); - $s += $this->a; - $e += $this->a; - parent::FilledArc($xc,$yc,$w,$h,$s,$e); - } - - function SetMargin($lm,$rm,$tm,$bm) { - parent::SetMargin($lm,$rm,$tm,$bm); - $this->dx=$this->left_margin+$this->plotwidth/2; - $this->dy=$this->top_margin+$this->plotheight/2; - $this->UpdateRotMatrice(); - } - - function Rotate($x,$y) { - // Optimization. Ignore rotation if Angle==0 || Angle==360 - if( $this->a == 0 || $this->a == 360 ) { - return array($x + $this->transx, $y + $this->transy ); - } - else { - $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx; - $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy; - return array($x1,$y1); - } - } - - function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { - list($toX,$toY) = $this->Rotate($toX,$toY); - parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix); - - } - - function ArrRotate($pnts) { - $n = count($pnts)-1; - for($i=0; $i < $n; $i+=2) { - list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]); - $pnts[$i] = $x; $pnts[$i+1] = $y; - } - return $pnts; - } - - function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { - list($x1,$y1) = $this->Rotate($x1,$y1); - list($x2,$y2) = $this->Rotate($x2,$y2); - parent::DashedLine($x1,$y1,$x2,$y2,$dash_length,$dash_space); - } - - function Line($x1,$y1,$x2,$y2) { - list($x1,$y1) = $this->Rotate($x1,$y1); - list($x2,$y2) = $this->Rotate($x2,$y2); - parent::Line($x1,$y1,$x2,$y2); - } - - function Rectangle($x1,$y1,$x2,$y2) { - // Rectangle uses Line() so it will be rotated through that call - parent::Rectangle($x1,$y1,$x2,$y2); - } - - function FilledRectangle($x1,$y1,$x2,$y2) { - if( $y1==$y2 || $x1==$x2 ) - $this->Line($x1,$y1,$x2,$y2); - else - $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); - } - - function Polygon($pnts,$closed=FALSE,$fast=FALSE) { - // Polygon uses Line() so it will be rotated through that call unless - // fast drawing routines are used in which case a rotate is needed - if( $fast ) { - parent::Polygon($this->ArrRotate($pnts)); - } - else { - parent::Polygon($pnts,$closed,$fast); - } - } - - function FilledPolygon($pnts) { - parent::FilledPolygon($this->ArrRotate($pnts)); - } - - function Point($x,$y) { - list($xp,$yp) = $this->Rotate($x,$y); - parent::Point($xp,$yp); - } - - function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { - list($xp,$yp) = $this->Rotate($x,$y); - return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug); - } -} - -//======================================================================= -// CLASS ImgStreamCache -// Description: Handle caching of graphs to files. All image output goes -// through this class -//======================================================================= -class ImgStreamCache { - private $cache_dir, $timeout=0; // Infinite timeout - //--------------- - // CONSTRUCTOR - function __construct($aCacheDir=CACHE_DIR) { - $this->cache_dir = $aCacheDir; - } - - //--------------- - // PUBLIC METHODS - - // Specify a timeout (in minutes) for the file. If the file is older then the - // timeout value it will be overwritten with a newer version. - // If timeout is set to 0 this is the same as infinite large timeout and if - // timeout is set to -1 this is the same as infinite small timeout - function SetTimeout($aTimeout) { - $this->timeout=$aTimeout; - } - - // Output image to browser and also write it to the cache - function PutAndStream($aImage,$aCacheFileName,$aInline,$aStrokeFileName) { - - // Check if we should always stroke the image to a file - if( _FORCE_IMGTOFILE ) { - $aStrokeFileName = _FORCE_IMGDIR.GenImgName(); - } - - if( $aStrokeFileName != '' ) { - - if( $aStrokeFileName == 'auto' ) { - $aStrokeFileName = GenImgName(); - } - - if( file_exists($aStrokeFileName) ) { - - // Wait for lock (to make sure no readers are trying to access the image) - $fd = fopen($aStrokeFileName,'w'); - $lock = flock($fd, LOCK_EX); - - // Since the image write routines only accepts a filename which must not - // exist we need to delete the old file first - if( !@unlink($aStrokeFileName) ) { - $lock = flock($fd, LOCK_UN); - JpGraphError::RaiseL(25111,$aStrokeFileName); - //(" Can't delete cached image $aStrokeFileName. Permission problem?"); - } - $aImage->Stream($aStrokeFileName); - $lock = flock($fd, LOCK_UN); - fclose($fd); - - } - else { - $aImage->Stream($aStrokeFileName); - } - - return; - } - - if( $aCacheFileName != '' && USE_CACHE) { - - $aCacheFileName = $this->cache_dir . $aCacheFileName; - if( file_exists($aCacheFileName) ) { - if( !$aInline ) { - // If we are generating image off-line (just writing to the cache) - // and the file exists and is still valid (no timeout) - // then do nothing, just return. - $diff=time()-filemtime($aCacheFileName); - if( $diff < 0 ) { - JpGraphError::RaiseL(25112,$aCacheFileName); - //(" Cached imagefile ($aCacheFileName) has file date in the future!!"); - } - if( $this->timeout>0 && ($diff <= $this->timeout*60) ) return; - } - - // Wait for lock (to make sure no readers are trying to access the image) - $fd = fopen($aCacheFileName,'w'); - $lock = flock($fd, LOCK_EX); - - if( !@unlink($aCacheFileName) ) { - $lock = flock($fd, LOCK_UN); - JpGraphError::RaiseL(25113,$aStrokeFileName); - //(" Can't delete cached image $aStrokeFileName. Permission problem?"); - } - $aImage->Stream($aCacheFileName); - $lock = flock($fd, LOCK_UN); - fclose($fd); - - } - else { - $this->MakeDirs(dirname($aCacheFileName)); - if( !is_writeable(dirname($aCacheFileName)) ) { - JpGraphError::RaiseL(25114,$aCacheFileName); - //('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); - } - $aImage->Stream($aCacheFileName); - } - - $res=true; - // Set group to specified - if( CACHE_FILE_GROUP != '' ) { - $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); - } - if( CACHE_FILE_MOD != '' ) { - $res = @chmod($aCacheFileName,CACHE_FILE_MOD); - } - if( !$res ) { - JpGraphError::RaiseL(25115,$aStrokeFileName); - //(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); - } - - $aImage->Destroy(); - if( $aInline ) { - if ($fh = @fopen($aCacheFileName, "rb") ) { - $aImage->Headers(); - fpassthru($fh); - return; - } - else { - JpGraphError::RaiseL(25116,$aFile);//(" Cant open file from cache [$aFile]"); - } - } - } - elseif( $aInline ) { - $aImage->Headers(); - $aImage->Stream(); - return; - } - } - - function IsValid($aCacheFileName) { - $aCacheFileName = $this->cache_dir.$aCacheFileName; - if ( USE_CACHE && file_exists($aCacheFileName) ) { - $diff=time()-filemtime($aCacheFileName); - if( $this->timeout>0 && ($diff > $this->timeout*60) ) { - return false; - } - else { - return true; - } - } - else { - return false; - } - } - - function StreamImgFile($aImage,$aCacheFileName) { - $aCacheFileName = $this->cache_dir.$aCacheFileName; - if ( $fh = @fopen($aCacheFileName, 'rb') ) { - $lock = flock($fh, LOCK_SH); - $aImage->Headers(); - fpassthru($fh); - $lock = flock($fh, LOCK_UN); - fclose($fh); - return true; - } - else { - JpGraphError::RaiseL(25117,$aCacheFileName);//(" Can't open cached image \"$aCacheFileName\" for reading."); - } - } - - // Check if a given image is in cache and in that case - // pass it directly on to web browser. Return false if the - // image file doesn't exist or exists but is to old - function GetAndStream($aImage,$aCacheFileName) { - if( $this->Isvalid($aCacheFileName) ) { - $this->StreamImgFile($aImage,$aCacheFileName); - } - else { - return false; - } - } - - //--------------- - // PRIVATE METHODS - // Create all necessary directories in a path - function MakeDirs($aFile) { - $dirs = array(); - // In order to better work when open_basedir is enabled - // we do not create directories in the root path - while ( $aFile != '/' && !(file_exists($aFile)) ) { - $dirs[] = $aFile.'/'; - $aFile = dirname($aFile); - } - for ($i = sizeof($dirs)-1; $i>=0; $i--) { - if(! @mkdir($dirs[$i],0777) ) { - JpGraphError::RaiseL(25118,$aFile);//(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); - } - // We also specify mode here after we have changed group. - // This is necessary if Apache user doesn't belong the - // default group and hence can't specify group permission - // in the previous mkdir() call - if( CACHE_FILE_GROUP != "" ) { - $res=true; - $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); - $res = @chmod($dirs[$i],0777); - if( !$res ) { - JpGraphError::RaiseL(25119,$aFile);//(" Can't set permissions for $aFile. Permission problems?"); - } - } - } - return true; - } -} // CLASS Cache - -?> +CreateImgCanvas($aWidth,$aHeight); + + if( $aSetAutoMargin ) { + $this->SetAutoMargin(); + } + + if( !$this->SetImgFormat($aFormat) ) { + JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); + } + $this->ttf = new TTF(); + $this->langconv = new LanguageConv(); + } + + // Enable interlacing in images + function SetInterlace($aFlg=true) { + $this->iInterlace=$aFlg; + } + + // Should we use anti-aliasing. Note: This really slows down graphics! + function SetAntiAliasing($aFlg=true) { + $this->use_anti_aliasing = $aFlg; + if( function_exists('imageantialias') ) { + imageantialias($this->img,$aFlg); + } + else { + JpGraphError::RaiseL(25128);//('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.') + } + } + + function GetAntiAliasing() { + return $this->use_anti_aliasing ; + } + + function CreateRawCanvas($aWidth=0,$aHeight=0) { + if( $aWidth <= 1 || $aHeight <= 1 ) { + JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); + } + + $this->img = @imagecreatetruecolor($aWidth, $aHeight); + if( $this->img < 1 ) { + JpGraphError::RaiseL(25126); + //die("Can't create truecolor image. Check that you really have GD2 library installed."); + } + $this->SetAlphaBlending(); + + if( $this->iInterlace ) { + imageinterlace($this->img,1); + } + if( $this->rgb != null ) { + $this->rgb->img = $this->img ; + } + else { + $this->rgb = new RGB($this->img); + } + } + + function CloneCanvasH() { + $oldimage = $this->img; + $this->CreateRawCanvas($this->width,$this->height); + imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height); + return $oldimage; + } + + function CreateImgCanvas($aWidth=0,$aHeight=0) { + + $old = array($this->img,$this->width,$this->height); + + $aWidth = round($aWidth); + $aHeight = round($aHeight); + + $this->width=$aWidth; + $this->height=$aHeight; + + + if( $aWidth==0 || $aHeight==0 ) { + // We will set the final size later. + // Note: The size must be specified before any other + // img routines that stroke anything are called. + $this->img = null; + $this->rgb = null; + return $old; + } + + $this->CreateRawCanvas($aWidth,$aHeight); + // Set canvas color (will also be the background color for a + // a pallett image + $this->SetColor($this->canvascolor); + $this->FilledRectangle(0,0,$aWidth-1,$aHeight-1); + + return $old ; + } + + function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) { + if( $aw === -1 ) { + $aw = $aWidth; + $ah = $aHeight; + $f = 'imagecopyresized'; + } + else { + $f = 'imagecopyresampled'; + } + $f($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah); + } + + function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) { + $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); + } + + function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { + if( $aMix == 100 ) { + $this->CopyCanvasH($this->img,$fromImg, + $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); + } + else { + if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) { + // Create a new canvas that will hold the re-scaled original from image + if( $toWidth <= 1 || $toHeight <= 1 ) { + JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.'); + } + + $tmpimg = @imagecreatetruecolor($toWidth, $toHeight); + + if( $tmpimg < 1 ) { + JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?'); + } + $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0, + $toWidth,$toHeight,$fromWidth,$fromHeight); + $fromImg = $tmpimg; + } + imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix); + } + } + + static function GetWidth($aImg=null) { + if( $aImg === null ) { + $aImg = $this->img; + } + return imagesx($aImg); + } + + static function GetHeight($aImg=null) { + if( $aImg === null ) { + $aImg = $this->img; + } + return imagesy($aImg); + } + + static function CreateFromString($aStr) { + $img = imagecreatefromstring($aStr); + if( $img === false ) { + JpGraphError::RaiseL(25085); + //('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.'); + } + return $img; + } + + function SetCanvasH($aHdl) { + $this->img = $aHdl; + $this->rgb->img = $aHdl; + } + + function SetCanvasColor($aColor) { + $this->canvascolor = $aColor ; + } + + function SetAlphaBlending($aFlg=true) { + ImageAlphaBlending($this->img,$aFlg); + } + + function SetAutoMargin() { + $min_bm=5; + $lm = min(40,$this->width/7); + $rm = min(20,$this->width/10); + $tm = max(5,$this->height/7); + $bm = max($min_bm,$this->height/6); + $this->SetMargin($lm,$rm,$tm,$bm); + } + + //--------------- + // PUBLIC METHODS + + function SetFont($family,$style=FS_NORMAL,$size=10) { + $this->font_family=$family; + $this->font_style=$style; + $this->font_size=$size; + $this->font_file=''; + if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ + ++$this->font_family; + } + if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file + + // Check that this PHP has support for TTF fonts + if( !function_exists('imagettfbbox') ) { + JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); + } + $this->font_file = $this->ttf->File($this->font_family,$this->font_style); + } + } + + // Get the specific height for a text string + function GetTextHeight($txt="",$angle=0) { + $tmp = preg_split('/\n/',$txt); + $n = count($tmp); + $m=0; + for($i=0; $i< $n; ++$i) { + $m = max($m,strlen($tmp[$i])); + } + + if( $this->font_family <= FF_FONT2+1 ) { + if( $angle==0 ) { + $h = imagefontheight($this->font_family); + if( $h === false ) { + JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); + } + + return $n*$h; + } + else { + $w = @imagefontwidth($this->font_family); + if( $w === false ) { + JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); + } + + return $m*$w; + } + } + else { + $bbox = $this->GetTTFBBox($txt,$angle); + return $bbox[1]-$bbox[5]+1; + } + } + + // Estimate font height + function GetFontHeight($angle=0) { + $txt = "XOMg"; + return $this->GetTextHeight($txt,$angle); + } + + // Approximate font width with width of letter "O" + function GetFontWidth($angle=0) { + $txt = 'O'; + return $this->GetTextWidth($txt,$angle); + } + + // Get actual width of text in absolute pixels. Note that the width is the + // texts projected with onto the x-axis. Call with angle=0 to get the true + // etxt width. + function GetTextWidth($txt,$angle=0) { + + $tmp = preg_split('/\n/',$txt); + $n = count($tmp); + if( $this->font_family <= FF_FONT2+1 ) { + + $m=0; + for($i=0; $i < $n; ++$i) { + $l=strlen($tmp[$i]); + if( $l > $m ) { + $m = $l; + } + } + + if( $angle==0 ) { + $w = @imagefontwidth($this->font_family); + if( $w === false ) { + JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); + } + return $m*$w; + } + else { + // 90 degrees internal so height becomes width + $h = @imagefontheight($this->font_family); + if( $h === false ) { + JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.'); + } + return $n*$h; + } + } + else { + // For TTF fonts we must walk through a lines and find the + // widest one which we use as the width of the multi-line + // paragraph + $m=0; + for( $i=0; $i < $n; ++$i ) { + $bbox = $this->GetTTFBBox($tmp[$i],$angle); + $mm = $bbox[2] - $bbox[0]; + if( $mm > $m ) + $m = $mm; + } + return $m; + } + } + + + // Draw text with a box around it + function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", + $shadowcolor=false,$paragraph_align="left", + $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { + + $oldx = $this->lastx; + $oldy = $this->lasty; + + if( !is_numeric($dir) ) { + if( $dir=="h" ) $dir=0; + elseif( $dir=="v" ) $dir=90; + else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); + } + + if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { + $width=$this->GetTextWidth($txt,$dir) ; + $height=$this->GetTextHeight($txt,$dir) ; + } + else { + $width=$this->GetBBoxWidth($txt,$dir) ; + $height=$this->GetBBoxHeight($txt,$dir) ; + } + + $height += 2*$ymarg; + $width += 2*$xmarg; + + if( $this->text_halign=="right" ) $x -= $width; + elseif( $this->text_halign=="center" ) $x -= $width/2; + + if( $this->text_valign=="bottom" ) $y -= $height; + elseif( $this->text_valign=="center" ) $y -= $height/2; + + $olda = $this->SetAngle(0); + + if( $shadowcolor ) { + $this->PushColor($shadowcolor); + $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth, + $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth, + $cornerradius); + $this->PopColor(); + $this->PushColor($fcolor); + $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg, + $x+$width,$y+$height-$ymarg, + $cornerradius); + $this->PopColor(); + $this->PushColor($bcolor); + $this->RoundedRectangle($x-$xmarg,$y-$ymarg, + $x+$width,$y+$height-$ymarg,$cornerradius); + $this->PopColor(); + } + else { + if( $fcolor ) { + $oc=$this->current_color; + $this->SetColor($fcolor); + $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); + $this->current_color=$oc; + } + if( $bcolor ) { + $oc=$this->current_color; + $this->SetColor($bcolor); + $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); + $this->current_color=$oc; + } + } + + $h=$this->text_halign; + $v=$this->text_valign; + $this->SetTextAlign("left","top"); + + $debug=false; + $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug); + + $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg, + $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg); + $this->SetTextAlign($h,$v); + + $this->SetAngle($olda); + $this->lastx = $oldx; + $this->lasty = $oldy; + + return $bb; + } + + // Draw text with a box around it. This time the box will be rotated + // with the text. The previous method will just make a larger enough non-rotated + // box to hold the text inside. + function StrokeBoxedText2($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", + $shadowcolor=false,$paragraph_align="left", + $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { + + // This version of boxed text will stroke a rotated box round the text + // thta will follow the angle of the text. + // This has two implications: + // 1) This methos will only support TTF fonts + // 2) The only two alignment that makes sense are centered or baselined + + if( $this->font_family <= FF_FONT2+1 ) { + JpGraphError::RaiseL(25131);//StrokeBoxedText2() Only support TTF fonts and not built in bitmap fonts + } + + $oldx = $this->lastx; + $oldy = $this->lasty; + $dir = $this->NormAngle($dir); + + if( !is_numeric($dir) ) { + if( $dir=="h" ) $dir=0; + elseif( $dir=="v" ) $dir=90; + else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); + } + + $width=$this->GetTextWidth($txt,0) + 2*$xmarg; + $height=$this->GetTextHeight($txt,0) + 2*$ymarg ; + $rect_width=$this->GetBBoxWidth($txt,$dir) ; + $rect_height=$this->GetBBoxHeight($txt,$dir) ; + + $baseline_offset = $this->bbox_cache[1]-1; + + if( $this->text_halign=="center" ) { + if( $dir >= 0 && $dir <= 90 ) { + + $x -= $rect_width/2; + $x += sin($dir*M_PI/180)*$height; + $y += $rect_height/2; + + } elseif( $dir >= 270 && $dir <= 360 ) { + + $x -= $rect_width/2; + $y -= $rect_height/2; + $y += cos($dir*M_PI/180)*$height; + + } elseif( $dir >= 90 && $dir <= 180 ) { + + $x += $rect_width/2; + $y += $rect_height/2; + $y += cos($dir*M_PI/180)*$height; + + } + else { + // $dir > 180 && $dir < 270 + $x += $rect_width/2; + $x += sin($dir*M_PI/180)*$height; + $y -= $rect_height/2; + } + } + + // Rotate the box around this point + $this->SetCenter($x,$y); + $olda = $this->SetAngle(-$dir); + + // We need to use adjusted coordinats for the box to be able + // to draw the box below the baseline. This cannot be done before since + // the rotating point must be the original x,y since that is arounbf the + // point where the text will rotate and we cannot change this since + // that is where the GD/GreeType will rotate the text + + + // For smaller <14pt font we need to do some additional + // adjustments to make it look good + if( $this->font_size < 14 ) { + $x -= 2; + $y += 2; + } + else { + // $y += $baseline_offset; + } + + if( $shadowcolor ) { + $this->PushColor($shadowcolor); + $this->FilledRectangle($x-$xmarg+$dropwidth,$y+$ymarg+$dropwidth-$height, + $x+$width+$dropwidth,$y+$ymarg+$dropwidth); + //$cornerradius); + $this->PopColor(); + $this->PushColor($fcolor); + $this->FilledRectangle($x-$xmarg, $y+$ymarg-$height, + $x+$width, $y+$ymarg); + //$cornerradius); + $this->PopColor(); + $this->PushColor($bcolor); + $this->Rectangle($x-$xmarg,$y+$ymarg-$height, + $x+$width,$y+$ymarg); + //$cornerradius); + $this->PopColor(); + } + else { + if( $fcolor ) { + $oc=$this->current_color; + $this->SetColor($fcolor); + $this->FilledRectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius); + $this->current_color=$oc; + } + if( $bcolor ) { + $oc=$this->current_color; + $this->SetColor($bcolor); + $this->Rectangle($x-$xmarg,$y+$ymarg-$height,$x+$width,$y+$ymarg);//,$cornerradius); + $this->current_color=$oc; + } + } + + if( $this->font_size < 14 ) { + $x += 2; + $y -= 2; + } + else { + + // Restore the original y before we stroke the text + // $y -= $baseline_offset; + + } + + $this->SetCenter(0,0); + $this->SetAngle($olda); + + $h=$this->text_halign; + $v=$this->text_valign; + if( $this->text_halign == 'center') { + $this->SetTextAlign('center','basepoint'); + } + else { + $this->SetTextAlign('basepoint','basepoint'); + } + + $debug=false; + $this->StrokeText($x, $y, $txt, $dir, $paragraph_align,$debug); + + $bb = array($x-$xmarg, $y+$height-$ymarg, + $x+$width, $y+$height-$ymarg, + $x+$width, $y-$ymarg, + $x-$xmarg, $y-$ymarg); + + $this->SetTextAlign($h,$v); + $this->SetAngle($olda); + + $this->lastx = $oldx; + $this->lasty = $oldy; + + return $bb; + } + + // Set text alignment + function SetTextAlign($halign,$valign="bottom") { + $this->text_halign=$halign; + $this->text_valign=$valign; + } + + function _StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$aDebug=false) { + + if( is_numeric($dir) && $dir!=90 && $dir!=0) + JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); + + $h=$this->GetTextHeight($txt); + $fh=$this->GetFontHeight(); + $w=$this->GetTextWidth($txt); + + if( $this->text_halign=="right") { + $x -= $dir==0 ? $w : $h; + } + elseif( $this->text_halign=="center" ) { + // For center we subtract 1 pixel since this makes the middle + // be prefectly in the middle + $x -= $dir==0 ? $w/2-1 : $h/2; + } + if( $this->text_valign=="top" ) { + $y += $dir==0 ? $h : $w; + } + elseif( $this->text_valign=="center" ) { + $y += $dir==0 ? $h/2 : $w/2; + } + + if( $dir==90 ) { + imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); + $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); + if( $aDebug ) { + // Draw bounding box + $this->PushColor('green'); + $this->Polygon($aBoundingBox,true); + $this->PopColor(); + } + } + else { + if( preg_match('/\n/',$txt) ) { + $tmp = preg_split('/\n/',$txt); + for($i=0; $i < count($tmp); ++$i) { + $w1 = $this->GetTextWidth($tmp[$i]); + if( $paragraph_align=="left" ) { + imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + } + elseif( $paragraph_align=="right" ) { + imagestring($this->img,$this->font_family,$x+($w-$w1),$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + } + else { + imagestring($this->img,$this->font_family,$x+$w/2-$w1/2,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + } + } + } + else { + //Put the text + imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); + } + if( $aDebug ) { + // Draw the bounding rectangle and the bounding box + $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); + + // Draw bounding box + $this->PushColor('green'); + $this->Polygon($p1,true); + $this->PopColor(); + + } + $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); + } + } + + function AddTxtCR($aTxt) { + // If the user has just specified a '\n' + // instead of '\n\t' we have to add '\r' since + // the width will be too muchy otherwise since when + // we print we stroke the individually lines by hand. + $e = explode("\n",$aTxt); + $n = count($e); + for($i=0; $i<$n; ++$i) { + $e[$i]=str_replace("\r","",$e[$i]); + } + return implode("\n\r",$e); + } + + function NormAngle($a) { + // Normalize angle in degrees + // Normalize angle to be between 0-360 + while( $a > 360 ) + $a -= 360; + while( $a < -360 ) + $a += 360; + if( $a < 0 ) + $a = 360 + $a; + return $a; + } + + function imagettfbbox_fixed($size, $angle, $fontfile, $text) { + + + if( ! USE_LIBRARY_IMAGETTFBBOX ) { + + $bbox = @imagettfbbox($size, $angle, $fontfile, $text); + if( $bbox === false ) { + JpGraphError::RaiseL(25092,$this->font_file); + //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); + } + $this->bbox_cache = $bbox; + return $bbox; + } + + // The built in imagettfbbox is buggy for angles != 0 so + // we calculate this manually by getting the bounding box at + // angle = 0 and then rotate the bounding box manually + $bbox = @imagettfbbox($size, 0, $fontfile, $text); + if( $bbox === false ) { + JpGraphError::RaiseL(25092,$this->font_file); + //("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); + } + + $angle = $this->NormAngle($angle); + + $a = $angle*M_PI/180; + $ca = cos($a); + $sa = sin($a); + $ret = array(); + + // We always add 1 pixel to the left since the left edge of the bounding + // box is sometimes coinciding with the first pixel of the text + //$bbox[0] -= 1; + //$bbox[6] -= 1; + + // For roatated text we need to add extra width for rotated + // text since the kerning and stroking of the TTF is not the same as for + // text at a 0 degree angle + + if( $angle > 0.001 && abs($angle-360) > 0.001 ) { + $h = abs($bbox[7]-$bbox[1]); + $w = abs($bbox[2]-$bbox[0]); + + $bbox[0] -= 2; + $bbox[6] -= 2; + // The width is underestimated so compensate for that + $bbox[2] += round($w*0.06); + $bbox[4] += round($w*0.06); + + // and we also need to compensate with increased height + $bbox[5] -= round($h*0.1); + $bbox[7] -= round($h*0.1); + + if( $angle > 90 ) { + // For angles > 90 we also need to extend the height further down + // by the baseline since that is also one more problem + $bbox[1] += round($h*0.15); + $bbox[3] += round($h*0.15); + + // and also make it slighty less height + $bbox[7] += round($h*0.05); + $bbox[5] += round($h*0.05); + + // And we need to move the box slightly top the rright (from a tetx perspective) + $bbox[0] += round($w*0.02); + $bbox[6] += round($w*0.02); + + if( $angle > 180 ) { + // And we need to move the box slightly to the left (from a text perspective) + $bbox[0] -= round($w*0.02); + $bbox[6] -= round($w*0.02); + $bbox[2] -= round($w*0.02); + $bbox[4] -= round($w*0.02); + + } + + } + for($i = 0; $i < 7; $i += 2) { + $ret[$i] = round($bbox[$i] * $ca + $bbox[$i+1] * $sa); + $ret[$i+1] = round($bbox[$i+1] * $ca - $bbox[$i] * $sa); + } + $this->bbox_cache = $ret; + return $ret; + } + else { + $this->bbox_cache = $bbox; + return $bbox; + } + } + + // Deprecated + function GetTTFBBox($aTxt,$aAngle=0) { + $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt); + return $bbox; + } + + function GetBBoxTTF($aTxt,$aAngle=0) { + // Normalize the bounding box to become a minimum + // enscribing rectangle + + $aTxt = $this->AddTxtCR($aTxt); + + if( !is_readable($this->font_file) ) { + JpGraphError::RaiseL(25093,$this->font_file); + //('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.'); + } + $bbox = $this->imagettfbbox_fixed($this->font_size,$aAngle,$this->font_file,$aTxt); + + if( $aAngle==0 ) return $bbox; + + if( $aAngle >= 0 ) { + if( $aAngle <= 90 ) { //<=0 + $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], + $bbox[2],$bbox[5],$bbox[6],$bbox[5]); + } + elseif( $aAngle <= 180 ) { //<= 2 + $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7], + $bbox[0],$bbox[3],$bbox[4],$bbox[3]); + } + elseif( $aAngle <= 270 ) { //<= 3 + $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], + $bbox[6],$bbox[1],$bbox[2],$bbox[1]); + } + else { + $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], + $bbox[4],$bbox[7],$bbox[0],$bbox[7]); + } + } + elseif( $aAngle < 0 ) { + if( $aAngle <= -270 ) { // <= -3 + $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], + $bbox[2],$bbox[5],$bbox[6],$bbox[5]); + } + elseif( $aAngle <= -180 ) { // <= -2 + $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], + $bbox[4],$bbox[7],$bbox[0],$bbox[7]); + } + elseif( $aAngle <= -90 ) { // <= -1 + $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], + $bbox[6],$bbox[1],$bbox[2],$bbox[1]); + } + else { + $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], + $bbox[4],$bbox[7],$bbox[0],$bbox[7]); + } + } + return $bbox; + } + + function GetBBoxHeight($aTxt,$aAngle=0) { + $box = $this->GetBBoxTTF($aTxt,$aAngle); + return abs($box[7]-$box[1]); + } + + function GetBBoxWidth($aTxt,$aAngle=0) { + $box = $this->GetBBoxTTF($aTxt,$aAngle); + return $box[2]-$box[0]+1; + } + + + function _StrokeTTF($x,$y,$txt,$dir,$paragraph_align,&$aBoundingBox,$debug=false) { + + // Setup default inter line margin for paragraphs to be + // 3% of the font height. + $ConstLineSpacing = 0.03 ; + + // Remember the anchor point before adjustment + if( $debug ) { + $ox=$x; + $oy=$y; + } + + if( !preg_match('/\n/',$txt) || ($dir>0 && preg_match('/\n/',$txt)) ) { + // Format a single line + + $txt = $this->AddTxtCR($txt); + $bbox=$this->GetBBoxTTF($txt,$dir); + $width = $this->GetBBoxWidth($txt,$dir); + $height = $this->GetBBoxHeight($txt,$dir); + + // The special alignment "basepoint" is mostly used internally + // in the library. This will put the anchor position at the left + // basepoint of the tetx. This is the default anchor point for + // TTF text. + + if( $this->text_valign != 'basepoint' ) { + // Align x,y ot lower left corner of bbox + + + if( $this->text_halign=='right' ) { + $x -= $width; + $x -= $bbox[0]; + } + elseif( $this->text_halign=='center' ) { + $x -= $width/2; + $x -= $bbox[0]; + } + elseif( $this->text_halign=='baseline' ) { + // This is only support for text at 90 degree !! + // Do nothing the text is drawn at baseline by default + } + + if( $this->text_valign=='top' ) { + $y -= $bbox[1]; // Adjust to bottom of text + $y += $height; + } + elseif( $this->text_valign=='center' ) { + $y -= $bbox[1]; // Adjust to bottom of text + $y += $height/2; + } + elseif( $this->text_valign=='baseline' ) { + // This is only support for text at 0 degree !! + // Do nothing the text is drawn at baseline by default + } + } + ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, + $this->current_color,$this->font_file,$txt); + + // Calculate and return the co-ordinates for the bounding box + $box = $this->imagettfbbox_fixed($this->font_size,$dir,$this->font_file,$txt); + $p1 = array(); + + for($i=0; $i < 4; ++$i) { + $p1[] = round($box[$i*2]+$x); + $p1[] = round($box[$i*2+1]+$y); + } + $aBoundingBox = $p1; + + // Debugging code to highlight the bonding box and bounding rectangle + // For text at 0 degrees the bounding box and bounding rectangle are the + // same + if( $debug ) { + // Draw the bounding rectangle and the bounding box + + $p = array(); + $p1 = array(); + + for($i=0; $i < 4; ++$i) { + $p[] = $bbox[$i*2]+$x ; + $p[] = $bbox[$i*2+1]+$y; + $p1[] = $box[$i*2]+$x ; + $p1[] = $box[$i*2+1]+$y ; + } + + // Draw bounding box + $this->PushColor('green'); + $this->Polygon($p1,true); + $this->PopColor(); + + // Draw bounding rectangle + $this->PushColor('darkgreen'); + $this->Polygon($p,true); + $this->PopColor(); + + // Draw a cross at the anchor point + $this->PushColor('red'); + $this->Line($ox-15,$oy,$ox+15,$oy); + $this->Line($ox,$oy-15,$ox,$oy+15); + $this->PopColor(); + } + } + else { + // Format a text paragraph + $fh=$this->GetFontHeight(); + + // Line margin is 25% of font height + $linemargin=round($fh*$ConstLineSpacing); + $fh += $linemargin; + $w=$this->GetTextWidth($txt); + + $y -= $linemargin/2; + $tmp = preg_split('/\n/',$txt); + $nl = count($tmp); + $h = $nl * $fh; + + if( $this->text_halign=='right') { + $x -= $dir==0 ? $w : $h; + } + elseif( $this->text_halign=='center' ) { + $x -= $dir==0 ? $w/2 : $h/2; + } + + if( $this->text_valign=='top' ) { + $y += $dir==0 ? $h : $w; + } + elseif( $this->text_valign=='center' ) { + $y += $dir==0 ? $h/2 : $w/2; + } + + // Here comes a tricky bit. + // Since we have to give the position for the string at the + // baseline this means thaht text will move slightly up + // and down depending on any of it's character descend below + // the baseline, for example a 'g'. To adjust the Y-position + // we therefore adjust the text with the baseline Y-offset + // as used for the current font and size. This will keep the + // baseline at a fixed positoned disregarding the actual + // characters in the string. + $standardbox = $this->GetTTFBBox('Gg',$dir); + $yadj = $standardbox[1]; + $xadj = $standardbox[0]; + $aBoundingBox = array(); + for($i=0; $i < $nl; ++$i) { + $wl = $this->GetTextWidth($tmp[$i]); + $bbox = $this->GetTTFBBox($tmp[$i],$dir); + if( $paragraph_align=='left' ) { + $xl = $x; + } + elseif( $paragraph_align=='right' ) { + $xl = $x + ($w-$wl); + } + else { + // Center + $xl = $x + $w/2 - $wl/2 ; + } + + // In theory we should adjust with full pre-lead to get the lines + // lined up but this doesn't look good so therfore we only adjust with + // half th pre-lead + $xl -= $bbox[0]/2; + $yl = $y - $yadj; + //$xl = $xl- $xadj; + ImageTTFText($this->img, $this->font_size, $dir, $xl, $yl-($h-$fh)+$fh*$i, + $this->current_color,$this->font_file,$tmp[$i]); + + // echo "xl=$xl,".$tmp[$i]."
      "; + if( $debug ) { + // Draw the bounding rectangle around each line + $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]); + $p = array(); + for($j=0; $j < 4; ++$j) { + $p[] = $bbox[$j*2]+$xl; + $p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i; + } + + // Draw bounding rectangle + $this->PushColor('darkgreen'); + $this->Polygon($p,true); + $this->PopColor(); + } + } + + // Get the bounding box + $bbox = $this->GetBBoxTTF($txt,$dir); + for($j=0; $j < 4; ++$j) { + $bbox[$j*2]+= round($x); + $bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj); + } + $aBoundingBox = $bbox; + + if( $debug ) { + // Draw a cross at the anchor point + $this->PushColor('red'); + $this->Line($ox-25,$oy,$ox+25,$oy); + $this->Line($ox,$oy-25,$ox,$oy+25); + $this->PopColor(); + } + + } + } + + function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { + + $x = round($x); + $y = round($y); + + // Do special language encoding + $txt = $this->langconv->Convert($txt,$this->font_family); + + if( !is_numeric($dir) ) { + JpGraphError::RaiseL(25094);//(" Direction for text most be given as an angle between 0 and 90."); + } + + if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { + $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); + } + elseif( $this->font_family >= _FIRST_FONT && $this->font_family <= _LAST_FONT) { + $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); + } + else { + JpGraphError::RaiseL(25095);//(" Unknown font font family specification. "); + } + return $boundingbox; + } + + function SetMargin($lm,$rm,$tm,$bm) { + $this->left_margin=$lm; + $this->right_margin=$rm; + $this->top_margin=$tm; + $this->bottom_margin=$bm; + $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; + $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; + if( $this->width > 0 && $this->height > 0 ) { + if( $this->plotwidth < 0 || $this->plotheight < 0 ) { + JpGraphError::RaiseL(25130, $this->plotwidth, $this->plotheight); + //JpGraphError::raise("To small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins."); + } + } + } + + function SetTransparent($color) { + imagecolortransparent ($this->img,$this->rgb->allocate($color)); + } + + function SetColor($color,$aAlpha=0) { + $this->current_color_name = $color; + $this->current_color=$this->rgb->allocate($color,$aAlpha); + if( $this->current_color == -1 ) { + $tc=imagecolorstotal($this->img); + JpGraphError::RaiseL(25096); + //("Can't allocate any more colors. Image has already allocated maximum of $tc colors. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\"USE_APPROX_COLORS\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); + } + return $this->current_color; + } + + function PushColor($color) { + if( $color != "" ) { + $this->colorstack[$this->colorstackidx]=$this->current_color_name; + $this->colorstack[$this->colorstackidx+1]=$this->current_color; + $this->colorstackidx+=2; + $this->SetColor($color); + } + else { + JpGraphError::RaiseL(25097);//("Color specified as empty string in PushColor()."); + } + } + + function PopColor() { + if( $this->colorstackidx < 1 ) { + JpGraphError::RaiseL(25098);//(" Negative Color stack index. Unmatched call to PopColor()"); + } + $this->current_color=$this->colorstack[--$this->colorstackidx]; + $this->current_color_name=$this->colorstack[--$this->colorstackidx]; + } + + + function SetLineWeight($weight) { + $old = $this->line_weight; + imagesetthickness($this->img,$weight); + $this->line_weight = $weight; + return $old; + } + + function SetStartPoint($x,$y) { + $this->lastx=round($x); + $this->lasty=round($y); + } + + function Arc($cx,$cy,$w,$h,$s,$e) { + // GD Arc doesn't like negative angles + while( $s < 0) $s += 360; + while( $e < 0) $e += 360; + imagearc($this->img,round($cx),round($cy),round($w),round($h),$s,$e,$this->current_color); + } + + function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { + $s = round($s); + $e = round($e); + while( $s < 0 ) $s += 360; + while( $e < 0 ) $e += 360; + if( $style=='' ) + $style=IMG_ARC_PIE; + if( abs($s-$e) > 0 ) { + imagefilledarc($this->img,round($xc),round($yc),round($w),round($h),$s,$e,$this->current_color,$style); + } + } + + function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) { + $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name); + } + + function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor="",$arccolor="") { + $s = round($s); $e = round($e); + $w = round($w); $h = round($h); + $xc = round($xc); $yc = round($yc); + if( $s == $e ) { + // A full circle. We draw this a plain circle + $this->PushColor($fillcolor); + imagefilledellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); + + // If antialiasing is used then we often don't have any color no the surrounding + // arc. So, we need to check for this special case so we don't send an empty + // color to the push function. In this case we use the fill color for the arc as well + if( $arccolor != '' ) { + $this->PopColor(); + $this->PushColor($arccolor); + } + imageellipse($this->img,$xc,$yc,2*$w,2*$h,$this->current_color); + $this->Line($xc,$yc,cos($s*M_PI/180)*$w+$xc,$yc+sin($s*M_PI/180)*$h); + $this->PopColor(); + } + else { + $this->PushColor($fillcolor); + $this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e); + $this->PopColor(); + if( $arccolor != "" ) { + $this->PushColor($arccolor); + // We add 2 pixels to make the Arc() better aligned with + // the filled arc. + imagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ; + $this->PopColor(); + } + } + } + + function Ellipse($xc,$yc,$w,$h) { + $this->Arc($xc,$yc,$w,$h,0,360); + } + + function Circle($xc,$yc,$r) { + imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color); + } + + function FilledCircle($xc,$yc,$r) { + imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color); + } + + // Linear Color InterPolation + function lip($f,$t,$p) { + $p = round($p,1); + $r = $f[0] + ($t[0]-$f[0])*$p; + $g = $f[1] + ($t[1]-$f[1])*$p; + $b = $f[2] + ($t[2]-$f[2])*$p; + return array($r,$g,$b); + } + + // Set line style dashed, dotted etc + function SetLineStyle($s) { + if( is_numeric($s) ) { + if( $s<1 || $s>4 ) { + JpGraphError::RaiseL(25101,$s);//(" Illegal numeric argument to SetLineStyle(): ($s)"); + } + } + elseif( is_string($s) ) { + if( $s == "solid" ) $s=1; + elseif( $s == "dotted" ) $s=2; + elseif( $s == "dashed" ) $s=3; + elseif( $s == "longdashed" ) $s=4; + else { + JpGraphError::RaiseL(25102,$s);//(" Illegal string argument to SetLineStyle(): $s"); + } + } + else { + JpGraphError::RaiseL(25103,$s);//(" Illegal argument to SetLineStyle $s"); + } + $old = $this->line_style; + $this->line_style=$s; + return $old; + } + + // Same as Line but take the line_style into account + function StyleLine($x1,$y1,$x2,$y2,$aStyle='') { + if( $this->line_weight <= 0 ) return; + + if( $aStyle === '' ) { + $aStyle = $this->line_style; + } + + // Add error check since dashed line will only work if anti-alias is disabled + // this is a limitation in GD + + if( $aStyle == 1 ) { + // Solid style. We can handle anti-aliasing for this + $this->Line($x1,$y1,$x2,$y2); + } + else { + // Since the GD routines doesn't handle AA for styled line + // we have no option than to turn it off to get any lines at + // all if the weight > 1 + $oldaa = $this->GetAntiAliasing(); + if( $oldaa && $this->line_weight > 1 ) { + $this->SetAntiAliasing(false); + } + + switch( $aStyle ) { + case 2: // Dotted + $this->DashedLine($x1,$y1,$x2,$y2,2,6); + break; + case 3: // Dashed + $this->DashedLine($x1,$y1,$x2,$y2,5,9); + break; + case 4: // Longdashes + $this->DashedLine($x1,$y1,$x2,$y2,9,13); + break; + default: + JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); + break; + } + if( $oldaa ) { + $this->SetAntiAliasing(true); + } + } + } + + function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { + + if( $this->line_weight <= 0 ) return; + + // Add error check to make sure anti-alias is not enabled. + // Dashed line does not work with anti-alias enabled. This + // is a limitation in GD. + if( $this->use_anti_aliasing ) { + JpGraphError::RaiseL(25129); // Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines. + } + + + $x1 = round($x1); + $x2 = round($x2); + $y1 = round($y1); + $y2 = round($y2); + + $style = array_fill(0,$dash_length,$this->current_color); + $style = array_pad($style,$dash_space,IMG_COLOR_TRANSPARENT); + imagesetstyle($this->img, $style); + imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + $this->lastx = $x2; + $this->lasty = $y2; + } + + function Line($x1,$y1,$x2,$y2) { + + if( $this->line_weight <= 0 ) return; + + $x1 = round($x1); + $x2 = round($x2); + $y1 = round($y1); + $y2 = round($y2); + + imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); + $this->lastx=$x2; + $this->lasty=$y2; + } + + function Polygon($p,$closed=FALSE,$fast=FALSE) { + + if( $this->line_weight <= 0 ) return; + + $n=count($p); + $oldx = $p[0]; + $oldy = $p[1]; + if( $fast ) { + for( $i=2; $i < $n; $i+=2 ) { + imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color); + $oldx = $p[$i]; + $oldy = $p[$i+1]; + } + if( $closed ) { + imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color); + } + } + else { + for( $i=2; $i < $n; $i+=2 ) { + $this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]); + $oldx = $p[$i]; + $oldy = $p[$i+1]; + } + if( $closed ) { + $this->StyleLine($oldx,$oldy,$p[0],$p[1]); + } + } + } + + function FilledPolygon($pts) { + $n=count($pts); + if( $n == 0 ) { + JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.'); + } + for($i=0; $i < $n; ++$i) { + $pts[$i] = round($pts[$i]); + } + $old = $this->line_weight; + imagesetthickness($this->img,1); + imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); + $this->line_weight = $old; + imagesetthickness($this->img,$old); + } + + function Rectangle($xl,$yu,$xr,$yl) { + $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu)); + } + + function FilledRectangle($xl,$yu,$xr,$yl) { + $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); + } + + function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) { + // Fill a rectangle with lines of two colors + if( $style===1 ) { + // Horizontal stripe + if( $yl < $yu ) { + $t = $yl; $yl=$yu; $yu=$t; + } + for( $y=$yu; $y <= $yl; ++$y) { + $this->SetColor($color1); + $this->Line($xl,$y,$xr,$y); + ++$y; + $this->SetColor($color2); + $this->Line($xl,$y,$xr,$y); + } + } + else { + if( $xl < $xl ) { + $t = $xl; $xl=$xr; $xr=$t; + } + for( $x=$xl; $x <= $xr; ++$x) { + $this->SetColor($color1); + $this->Line($x,$yu,$x,$yl); + ++$x; + $this->SetColor($color2); + $this->Line($x,$yu,$x,$yl); + } + } + } + + function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=4,$shadow_color='darkgray',$useAlpha=true) { + // This is complicated by the fact that we must also handle the case where + // the reactangle has no fill color + $xl = floor($xl); + $yu = floor($yu); + $xr = floor($xr); + $yl = floor($yl); + $this->PushColor($shadow_color); + $shadowAlpha=0; + $this->SetLineWeight(1); + $this->SetLineStyle('solid'); + $basecolor = $this->rgb->Color($shadow_color); + $shadow_color = array($basecolor[0],$basecolor[1],$basecolor[2],); + for( $i=0; $i < $shadow_width; ++$i ) { + $this->SetColor($shadow_color,$shadowAlpha); + $this->Line($xr-$shadow_width+$i, $yu+$shadow_width, + $xr-$shadow_width+$i, $yl-$shadow_width-1+$i); + $this->Line($xl+$shadow_width, $yl-$shadow_width+$i, + $xr-$shadow_width+$i, $yl-$shadow_width+$i); + if( $useAlpha ) $shadowAlpha += 1.0/$shadow_width; + } + + $this->PopColor(); + if( $fcolor==false ) { + $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); + } + else { + $this->PushColor($fcolor); + $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); + $this->PopColor(); + $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); + } + } + + function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) { + if( $r==0 ) { + $this->FilledRectangle($xt,$yt,$xr,$yl); + return; + } + + // To avoid overlapping fillings (which will look strange + // when alphablending is enabled) we have no choice but + // to fill the five distinct areas one by one. + + // Center square + $this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r); + // Top band + $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r); + // Bottom band + $this->FilledRectangle($xt+$r,$yl-$r,$xr-$r,$yl); + // Left band + $this->FilledRectangle($xt,$yt+$r,$xt+$r,$yl-$r); + // Right band + $this->FilledRectangle($xr-$r,$yt+$r,$xr,$yl-$r); + + // Topleft & Topright arc + $this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Bottomleft & Bottom right arc + $this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + } + + function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) { + + if( $r==0 ) { + $this->Rectangle($xt,$yt,$xr,$yl); + return; + } + + // Top & Bottom line + $this->Line($xt+$r,$yt,$xr-$r,$yt); + $this->Line($xt+$r,$yl,$xr-$r,$yl); + + // Left & Right line + $this->Line($xt,$yt+$r,$xt,$yl-$r); + $this->Line($xr,$yt+$r,$xr,$yl-$r); + + // Topleft & Topright arc + $this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Bottomleft & Bottomright arc + $this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + } + + function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') { + $this->FilledRectangle($x1,$y1,$x2,$y2); + $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2); + } + + function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') { + $this->PushColor($color1); + for( $i=0; $i < $depth; ++$i ) { + $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i); + $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i); + } + $this->PopColor(); + + $this->PushColor($color2); + for( $i=0; $i < $depth; ++$i ) { + $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i); + $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1); + } + $this->PopColor(); + } + + function StyleLineTo($x,$y) { + $this->StyleLine($this->lastx,$this->lasty,$x,$y); + $this->lastx=$x; + $this->lasty=$y; + } + + function LineTo($x,$y) { + $this->Line($this->lastx,$this->lasty,$x,$y); + $this->lastx=$x; + $this->lasty=$y; + } + + function Point($x,$y) { + imagesetpixel($this->img,round($x),round($y),$this->current_color); + } + + function Fill($x,$y) { + imagefill($this->img,round($x),round($y),$this->current_color); + } + + function FillToBorder($x,$y,$aBordColor) { + $bc = $this->rgb->allocate($aBordColor); + if( $bc == -1 ) { + JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors'); + } + imagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color); + } + + function SetExpired($aFlg=true) { + $this->expired = $aFlg; + } + + // Generate image header + function Headers() { + + // In case we are running from the command line with the client version of + // PHP we can't send any headers. + $sapi = php_sapi_name(); + if( $sapi == 'cli' ) return; + + // These parameters are set by headers_sent() but they might cause + // an undefined variable error unless they are initilized + $file=''; + $lineno=''; + if( headers_sent($file,$lineno) ) { + $file=basename($file); + $t = new ErrMsgText(); + $msg = $t->Get(10,$file,$lineno); + die($msg); + } + + if ($this->expired) { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + } + header("Content-type: image/$this->img_format"); + } + + // Adjust image quality for formats that allow this + function SetQuality($q) { + $this->quality = $q; + } + + // Stream image to browser or to file + function Stream($aFile="") { + $func="image".$this->img_format; + if( $this->img_format=="jpeg" && $this->quality != null ) { + $res = @$func($this->img,$aFile,$this->quality); + } + else { + if( $aFile != "" ) { + $res = @$func($this->img,$aFile); + if( !$res ) { + JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); + } + } + else { + $res = @$func($this->img); + if( !$res ) { + JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); + } + + } + } + } + + // Clear resources used by image (this is normally not used since all resources are/should be + // returned when the script terminates + function Destroy() { + imagedestroy($this->img); + } + + // Specify image format. Note depending on your installation + // of PHP not all formats may be supported. + function SetImgFormat($aFormat,$aQuality=75) { + $this->quality = $aQuality; + $aFormat = strtolower($aFormat); + $tst = true; + $supported = imagetypes(); + if( $aFormat=="auto" ) { + if( $supported & IMG_PNG ) $this->img_format="png"; + elseif( $supported & IMG_JPG ) $this->img_format="jpeg"; + elseif( $supported & IMG_GIF ) $this->img_format="gif"; + elseif( $supported & IMG_WBMP ) $this->img_format="wbmp"; + elseif( $supported & IMG_XPM ) $this->img_format="xpm"; + else { + JpGraphError::RaiseL(25109);//("Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details."); + } + return true; + } + else { + if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { + if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) $tst=false; + elseif( $aFormat=="png" && !($supported & IMG_PNG) ) $tst=false; + elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) $tst=false; + elseif( $aFormat=="wbmp" && !($supported & IMG_WBMP) ) $tst=false; + elseif( $aFormat=="xpm" && !($supported & IMG_XPM) ) $tst=false; + else { + $this->img_format=$aFormat; + return true; + } + } + else { + $tst=false; + } + if( !$tst ) { + JpGraphError::RaiseL(25110,$aFormat);//(" Your PHP installation does not support the chosen graphic format: $aFormat"); + } + } + } +} // CLASS + +//=================================================== +// CLASS RotImage +// Description: Exactly as Image but draws the image at +// a specified angle around a specified rotation point. +//=================================================== +class RotImage extends Image { + public $a=0; + public $dx=0,$dy=0,$transx=0,$transy=0; + private $m=array(); + + function __construct($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { + parent::__construct($aWidth,$aHeight,$aFormat,$aSetAutoMargin); + $this->dx=$this->left_margin+$this->plotwidth/2; + $this->dy=$this->top_margin+$this->plotheight/2; + $this->SetAngle($a); + } + + function SetCenter($dx,$dy) { + $old_dx = $this->dx; + $old_dy = $this->dy; + $this->dx=$dx; + $this->dy=$dy; + $this->SetAngle($this->a); + return array($old_dx,$old_dy); + } + + function SetTranslation($dx,$dy) { + $old = array($this->transx,$this->transy); + $this->transx = $dx; + $this->transy = $dy; + return $old; + } + + function UpdateRotMatrice() { + $a = $this->a; + $a *= M_PI/180; + $sa=sin($a); $ca=cos($a); + // Create the rotation matrix + $this->m[0][0] = $ca; + $this->m[0][1] = -$sa; + $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ; + $this->m[1][0] = $sa; + $this->m[1][1] = $ca; + $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ; + } + + function SetAngle($a) { + $tmp = $this->a; + $this->a = $a; + $this->UpdateRotMatrice(); + return $tmp; + } + + function Circle($xc,$yc,$r) { + list($xc,$yc) = $this->Rotate($xc,$yc); + parent::Circle($xc,$yc,$r); + } + + function FilledCircle($xc,$yc,$r) { + list($xc,$yc) = $this->Rotate($xc,$yc); + parent::FilledCircle($xc,$yc,$r); + } + + + function Arc($xc,$yc,$w,$h,$s,$e) { + list($xc,$yc) = $this->Rotate($xc,$yc); + $s += $this->a; + $e += $this->a; + parent::Arc($xc,$yc,$w,$h,$s,$e); + } + + function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { + list($xc,$yc) = $this->Rotate($xc,$yc); + $s += $this->a; + $e += $this->a; + parent::FilledArc($xc,$yc,$w,$h,$s,$e); + } + + function SetMargin($lm,$rm,$tm,$bm) { + parent::SetMargin($lm,$rm,$tm,$bm); + $this->dx=$this->left_margin+$this->plotwidth/2; + $this->dy=$this->top_margin+$this->plotheight/2; + $this->UpdateRotMatrice(); + } + + function Rotate($x,$y) { + // Optimization. Ignore rotation if Angle==0 || Angle==360 + if( $this->a == 0 || $this->a == 360 ) { + return array($x + $this->transx, $y + $this->transy ); + } + else { + $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx; + $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy; + return array($x1,$y1); + } + } + + function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { + list($toX,$toY) = $this->Rotate($toX,$toY); + parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix); + + } + + function ArrRotate($pnts) { + $n = count($pnts)-1; + for($i=0; $i < $n; $i+=2) { + list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]); + $pnts[$i] = $x; $pnts[$i+1] = $y; + } + return $pnts; + } + + function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { + list($x1,$y1) = $this->Rotate($x1,$y1); + list($x2,$y2) = $this->Rotate($x2,$y2); + parent::DashedLine($x1,$y1,$x2,$y2,$dash_length,$dash_space); + } + + function Line($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->Rotate($x1,$y1); + list($x2,$y2) = $this->Rotate($x2,$y2); + parent::Line($x1,$y1,$x2,$y2); + } + + function Rectangle($x1,$y1,$x2,$y2) { + // Rectangle uses Line() so it will be rotated through that call + parent::Rectangle($x1,$y1,$x2,$y2); + } + + function FilledRectangle($x1,$y1,$x2,$y2) { + if( $y1==$y2 || $x1==$x2 ) + $this->Line($x1,$y1,$x2,$y2); + else + $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); + } + + function Polygon($pnts,$closed=FALSE,$fast=FALSE) { + // Polygon uses Line() so it will be rotated through that call unless + // fast drawing routines are used in which case a rotate is needed + if( $fast ) { + parent::Polygon($this->ArrRotate($pnts)); + } + else { + parent::Polygon($pnts,$closed,$fast); + } + } + + function FilledPolygon($pnts) { + parent::FilledPolygon($this->ArrRotate($pnts)); + } + + function Point($x,$y) { + list($xp,$yp) = $this->Rotate($x,$y); + parent::Point($xp,$yp); + } + + function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { + list($xp,$yp) = $this->Rotate($x,$y); + return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug); + } +} + +//======================================================================= +// CLASS ImgStreamCache +// Description: Handle caching of graphs to files. All image output goes +// through this class +//======================================================================= +class ImgStreamCache { + private $cache_dir, $timeout=0; // Infinite timeout + //--------------- + // CONSTRUCTOR + function __construct($aCacheDir=CACHE_DIR) { + $this->cache_dir = $aCacheDir; + } + + //--------------- + // PUBLIC METHODS + + // Specify a timeout (in minutes) for the file. If the file is older then the + // timeout value it will be overwritten with a newer version. + // If timeout is set to 0 this is the same as infinite large timeout and if + // timeout is set to -1 this is the same as infinite small timeout + function SetTimeout($aTimeout) { + $this->timeout=$aTimeout; + } + + // Output image to browser and also write it to the cache + function PutAndStream($aImage,$aCacheFileName,$aInline,$aStrokeFileName) { + + // Check if we should always stroke the image to a file + if( _FORCE_IMGTOFILE ) { + $aStrokeFileName = _FORCE_IMGDIR.GenImgName(); + } + + if( $aStrokeFileName != '' ) { + + if( $aStrokeFileName == 'auto' ) { + $aStrokeFileName = GenImgName(); + } + + if( file_exists($aStrokeFileName) ) { + + // Wait for lock (to make sure no readers are trying to access the image) + $fd = fopen($aStrokeFileName,'w'); + $lock = flock($fd, LOCK_EX); + + // Since the image write routines only accepts a filename which must not + // exist we need to delete the old file first + if( !@unlink($aStrokeFileName) ) { + $lock = flock($fd, LOCK_UN); + JpGraphError::RaiseL(25111,$aStrokeFileName); + //(" Can't delete cached image $aStrokeFileName. Permission problem?"); + } + $aImage->Stream($aStrokeFileName); + $lock = flock($fd, LOCK_UN); + fclose($fd); + + } + else { + $aImage->Stream($aStrokeFileName); + } + + return; + } + + if( $aCacheFileName != '' && USE_CACHE) { + + $aCacheFileName = $this->cache_dir . $aCacheFileName; + if( file_exists($aCacheFileName) ) { + if( !$aInline ) { + // If we are generating image off-line (just writing to the cache) + // and the file exists and is still valid (no timeout) + // then do nothing, just return. + $diff=time()-filemtime($aCacheFileName); + if( $diff < 0 ) { + JpGraphError::RaiseL(25112,$aCacheFileName); + //(" Cached imagefile ($aCacheFileName) has file date in the future!!"); + } + if( $this->timeout>0 && ($diff <= $this->timeout*60) ) return; + } + + // Wait for lock (to make sure no readers are trying to access the image) + $fd = fopen($aCacheFileName,'w'); + $lock = flock($fd, LOCK_EX); + + if( !@unlink($aCacheFileName) ) { + $lock = flock($fd, LOCK_UN); + JpGraphError::RaiseL(25113,$aStrokeFileName); + //(" Can't delete cached image $aStrokeFileName. Permission problem?"); + } + $aImage->Stream($aCacheFileName); + $lock = flock($fd, LOCK_UN); + fclose($fd); + + } + else { + $this->MakeDirs(dirname($aCacheFileName)); + if( !is_writeable(dirname($aCacheFileName)) ) { + JpGraphError::RaiseL(25114,$aCacheFileName); + //('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); + } + $aImage->Stream($aCacheFileName); + } + + $res=true; + // Set group to specified + if( CACHE_FILE_GROUP != '' ) { + $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); + } + if( CACHE_FILE_MOD != '' ) { + $res = @chmod($aCacheFileName,CACHE_FILE_MOD); + } + if( !$res ) { + JpGraphError::RaiseL(25115,$aStrokeFileName); + //(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); + } + + $aImage->Destroy(); + if( $aInline ) { + if ($fh = @fopen($aCacheFileName, "rb") ) { + $aImage->Headers(); + fpassthru($fh); + return; + } + else { + JpGraphError::RaiseL(25116,$aFile);//(" Cant open file from cache [$aFile]"); + } + } + } + elseif( $aInline ) { + $aImage->Headers(); + $aImage->Stream(); + return; + } + } + + function IsValid($aCacheFileName) { + $aCacheFileName = $this->cache_dir.$aCacheFileName; + if ( USE_CACHE && file_exists($aCacheFileName) ) { + $diff=time()-filemtime($aCacheFileName); + if( $this->timeout>0 && ($diff > $this->timeout*60) ) { + return false; + } + else { + return true; + } + } + else { + return false; + } + } + + function StreamImgFile($aImage,$aCacheFileName) { + $aCacheFileName = $this->cache_dir.$aCacheFileName; + if ( $fh = @fopen($aCacheFileName, 'rb') ) { + $lock = flock($fh, LOCK_SH); + $aImage->Headers(); + fpassthru($fh); + $lock = flock($fh, LOCK_UN); + fclose($fh); + return true; + } + else { + JpGraphError::RaiseL(25117,$aCacheFileName);//(" Can't open cached image \"$aCacheFileName\" for reading."); + } + } + + // Check if a given image is in cache and in that case + // pass it directly on to web browser. Return false if the + // image file doesn't exist or exists but is to old + function GetAndStream($aImage,$aCacheFileName) { + if( $this->Isvalid($aCacheFileName) ) { + $this->StreamImgFile($aImage,$aCacheFileName); + } + else { + return false; + } + } + + //--------------- + // PRIVATE METHODS + // Create all necessary directories in a path + function MakeDirs($aFile) { + $dirs = array(); + // In order to better work when open_basedir is enabled + // we do not create directories in the root path + while ( $aFile != '/' && !(file_exists($aFile)) ) { + $dirs[] = $aFile.'/'; + $aFile = dirname($aFile); + } + for ($i = sizeof($dirs)-1; $i>=0; $i--) { + if(! @mkdir($dirs[$i],0777) ) { + JpGraphError::RaiseL(25118,$aFile);//(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); + } + // We also specify mode here after we have changed group. + // This is necessary if Apache user doesn't belong the + // default group and hence can't specify group permission + // in the previous mkdir() call + if( CACHE_FILE_GROUP != "" ) { + $res=true; + $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); + $res = @chmod($dirs[$i],0777); + if( !$res ) { + JpGraphError::RaiseL(25119,$aFile);//(" Can't set permissions for $aFile. Permission problems?"); + } + } + } + return true; + } +} // CLASS Cache + +?> diff --git a/ext/jpgraph-3.0.7/src/imgdata_balls.inc.php b/ext/jpgraph-3.0.7/src/imgdata_balls.inc.php index fda6a8f..a4b92b3 100644 --- a/ext/jpgraph-3.0.7/src/imgdata_balls.inc.php +++ b/ext/jpgraph-3.0.7/src/imgdata_balls.inc.php @@ -1,1061 +1,1061 @@ - 'imgdata_large', - MARK_IMG_MBALL => 'imgdata_small', - MARK_IMG_SBALL => 'imgdata_xsmall', - MARK_IMG_BALL => 'imgdata_xsmall'); - protected $colors,$index,$maxidx; - private $colors_1 = array('blue','lightblue','brown','darkgreen', - 'green','purple','red','gray','yellow','silver','gray'); - private $index_1 = array('blue'=>9,'lightblue'=>1,'brown'=>6,'darkgreen'=>7, - 'green'=>8,'purple'=>4,'red'=>0,'gray'=>5,'silver'=>3,'yellow'=>2); - private $maxidx_1 = 9 ; - - private $colors_2 = array('blue','bluegreen','brown','cyan', - 'darkgray','greengray','gray','green', - 'greenblue','lightblue','lightred', - 'purple','red','white','yellow'); - - - private $index_2 = array('blue'=>9,'bluegreen'=>13,'brown'=>8,'cyan'=>12, - 'darkgray'=>5,'greengray'=>6,'gray'=>2,'green'=>10, - 'greenblue'=>3,'lightblue'=>1,'lightred'=>14, - 'purple'=>7,'red'=>0,'white'=>11,'yellow'=>4); - - private $maxidx_2 = 14 ; - - - private $colors_3 = array('bluegreen','cyan','darkgray','greengray', - 'gray','graypurple','green','greenblue','lightblue', - 'lightred','navy','orange','purple','red','yellow'); - - private $index_3 = array('bluegreen'=>1,'cyan'=>11,'darkgray'=>14,'greengray'=>10, - 'gray'=>3,'graypurple'=>4,'green'=>9,'greenblue'=>7, - 'lightblue'=>13,'lightred'=>0,'navy'=>2,'orange'=>12, - 'purple'=>8,'red'=>5,'yellow'=>6); - private $maxidx_3 = 14 ; - - protected $imgdata_large, $imgdata_small, $imgdata_xsmall ; - - - function GetImg($aMark,$aIdx) { - switch( $aMark ) { - case MARK_IMG_SBALL: - case MARK_IMG_BALL: - $this->colors = $this->colors_3; - $this->index = $this->index_3 ; - $this->maxidx = $this->maxidx_3 ; - break; - case MARK_IMG_MBALL: - $this->colors = $this->colors_2; - $this->index = $this->index_2 ; - $this->maxidx = $this->maxidx_2 ; - break; - default: - $this->colors = $this->colors_1; - $this->index = $this->index_1 ; - $this->maxidx = $this->maxidx_1 ; - break; - } - return parent::GetImg($aMark,$aIdx); - } - - function __construct() { - - //========================================================== - // File: bl_red.png - //========================================================== - $this->imgdata_large[0][0]= 1072 ; - $this->imgdata_large[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAByF'. - 'BMVEX/////////xsb/vb3/lIz/hIT/e3v/c3P/c2v/a2v/Y2P/'. - 'UlL/Skr/SkL/Qjn/MTH/MSn/KSn/ISH/IRj/GBj/GBD/EBD/EA'. - 'j/CAj/CAD/AAD3QkL3MTH3KSn3KSH3GBj3EBD3CAj3AAD1zMzv'. - 'QkLvISHvIRjvGBjvEBDvEAjvAADnUlLnSkrnMTnnKSnnIRjnGB'. - 'DnEBDnCAjnAADec3PeSkreISHeGBjeGBDeEAjWhITWa2vWUlLW'. - 'SkrWISnWGBjWEBDWEAjWCAjWAADOnp7Oa2vOGCHOGBjOGBDOEB'. - 'DOCAjOAADJrq7Gt7fGGBjGEBDGCAjGAADEpKS/v7+9QkK9GBC9'. - 'EBC9CAi9AAC1e3u1a2u1Skq1KSm1EBC1CAi1AACtEBCtCBCtCA'. - 'itAACngYGlCAilAACghIScOTmcCAicAACYgYGUGAiUCAiUAAiU'. - 'AACMKSmMEACMAACEa2uEGAiEAAB7GBh7CAB7AABzOTlzGBBzCA'. - 'BzAABrSkprOTlrGBhrAABjOTljAABaQkJaOTlaCABaAABSKSlS'. - 'GBhSAABKKSlKGBhKAABCGBhCCABCAAA5CAA5AAAxCAAxAAApCA'. - 'ApAAAhAAAYAACc9eRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. - 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFD'. - 'UHLytKAAAB4UlEQVR4nGNgIAK4mGjrmNq6BmFIWMmISUpKSmk5'. - 'B8ZEokj4qoiLiQCBgqald3xaBpKMj6y4sLCQkJCIvIaFV0RaUR'. - 'lCSk5cWEiAn19ASN7QwisuraihHiajKyEixM/NwckjoKrvEACU'. - 'qumpg7pAUlREiJdNmZmLT9/cMzwps7Smc3I2WEpGUkxYkJuFiY'. - 'lTxszePzY1v7Shc2oX2D+K4iLCgjzsrOw8embuYUmZeTVtPVOn'. - 'gqSslYAOF+Ln4ZHWtXMPTcjMrWno7J82rRgoZWOsqaCgrqaqqm'. - 'fn5peQmlsK1DR52vRaoFSIs5GRoYG5ub27n19CYm5pdVPnxKnT'. - 'pjWDpLydnZwcHTz8QxMSEnJLgDL9U6dNnQ6Sio4PDAgICA+PTU'. - 'zNzSkph8hADIxKS46Pj0tKTc3MLSksqWrtmQySAjuDIT8rKy0r'. - 'Kz+vtLSmur6jb9JUIJgGdjxDQUVRUVFpaUVNQ1NrZ9+kKVOmTZ'. - 'k6vR0sldJUAwQNTU2dnX0TgOJTQLrSIYFY2dPW1NbW2TNxwtQp'. - 'U6ZMmjJt2rRGWNB3TO7vnzh5MsgSoB6gy7sREdY7bRrQEDAGOb'. - 'wXOQW0TJsOEpwClmxBTTbZ7UDVIPkp7dkYaYqhuLa5trYYUxwL'. - 'AADzm6uekAAcXAAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bl_bluegreen.png - //========================================================== - $this->imgdata_large[1][0]= 1368 ; - $this->imgdata_large[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMMFi8hE9b2uAAABOVJREFUeNq9lk2sJFUVx3+3qv'. - 'tW95t57zFvhiFxmCFRUJRoNCQiJARMhiFx/Igxii5goTG6ZDAu'. - '/EhcSCIrTAgLEiKsJ8ywABNZEMJXEDYCukAmjgjzBkK/j35V1d'. - '333FtV97io97pfzwxfG86qcu/N+Z3zP+fcW/Apmfk4hx57+R/6'. - 'Rqmc9ykhsWjlsUngAA1fXIQ7b73pI/186IGHnn9dH/8frC8v4I'. - 'PiG53uaerR4GmKkv31mB8cyfjd946ZTwR66qVX9OTWIi8UKUv9'. - 'BOrZXpYZvFeiBvzI0fgSUSFKwbVG+Pl1V3HH0VvNR4KeeukV/f'. - 'PmMmdHhst76aXD64AbeVQ9bjNHaiGOC2o3wLrAb2/4LL/84ffn'. - 'fCdzkOdayKpLppBemrBsU5Y1Zdmm9LJdGU6E/t4M24Q26jRDRL'. - 'j3mdc49cSTekFsMzs5XuTsyLDUNSDQ25NwKOly9YIl22MYhJr/'. - 'uoDtBBoT0CxBRGYOAhibIaOCe//2MpfM6KHnX9cXipSlbkKWmS'. - 'nk9iv38J0jixw7vJfrTMYBOvhSoQHJBS09ANELloAGDxW8tfoW'. - 'J+5/UC8CPS0LU7r3SpYarr7M8rmFjMPLXT6/33L4si7Z2GCrQC'. - '+0ctlOaNs9DReV8vSLr85ndPLpZ/WNvHW+01kAVFBOGvJx0wYg'. - 'Sp47RIQ4Emwa8FGJXlDxSCFo5YlVgAo2hwPue/hRndboTV3EW2'. - 'Wp3k6wBp8q56QiWzecW6vwQfnPRkAWhFgILnq08jQ+R2nlUzzN'. - 'uES9Q7Vd+9fba7NmWJW61db2247qACmcjxXr45psYphsFGSLBu'. - 'kIajxqtjNwHkvAjQt0sg3crhPA2+fPz0CuyNFOghsGsr19mnFg'. - 'DGwrRm8UoAtNmQPQtRXDgdC4HImCFEKcCE0oieUWUYq2LtbiGp'. - 'mBQmppfIkjw45DK0QNNkvQ0jMBtPL0UnDRM1rN+cxKwzvOo2NP'. - 'tykR9a1kfpZNDLMG6QDYJqCTBvUe1+uxs+YKyPoGrTwY2HhvC4'. - 'CDWQd5d4xNApNQEEMgjgLdUCLBQ5cprL/trwNwKG2IUmDqDFd5'. - 'sr5BWrlxuSdLDFEFlqAzXGc4zFjupqh6uqYihpxJcEgp026l2w'. - '7wFUv7Z6AvrfRo/n0OYzPwIKE3HUKAJg2otMBiElnsF7wngis9'. - '3ZDjNnLi7huCWUZfueZKTu/M0V3HvmkOFDVxVKDG04ScejSgW5'. - 'V0q5JYFEghuDLHlTmToqDeGOCKIVtrW9hsdmXufEcNLPSXuPHa'. - 'a+bvuh9df5AH/v5PDFmbWQC3Mx+TVvfGVTRB2CodNgT2JBX003'. - 'aANZAYS/BxCv32TV/l2C03G7jgmfjGiT/qmeEmibEYm7XzAO2k'. - 'A+pbgHhBgydqu54YO5eRiLCy7yDvPP6Xqf+5Z+Lu277OYuOpiw'. - 'H15oBmlNOMcmK5RbP+PrEscGU+DSAxdg4CICIkxnLP8aNz63Og'. - 'H3/rdvOb795GVhuaYo0oBc3GGrEsUPVTwO6a7LYd+X51x3Hu/t'. - 'lP5tS65FN+6okn9U+n/sqb596dTvhOF+02myXTmkQNrOw7yD3H'. - 'j14E+UDQjp24/0E9/eKrbA4HH3aMK1b2ccvXvswjv//1J/s5ud'. - 'Due/hRPfP+OmfOrk7vrn7a48ihA3zh8CH+8Iuffiw/n4r9H1ZZ'. - '0zz7G56hAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bl_yellow.png - //========================================================== - $this->imgdata_large[2][0]= 1101 ; - $this->imgdata_large[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. - 'BMVEX//////////+///+f//9b//8b//73//7X//63//6X//5T/'. - '/4z//4T//3P//2v//1r//0r//0L//zH//yn//yH//xj//xD//w'. - 'j//wD/90L/9zn/9zH/9xj/9xD/9wj/9wD39yn37zn37zH37yH3'. - '7xD37wj37wDv70Lv50rv50Lv5znv5yHv5xjv5wjv5wDn51Ln5x'. - 'Dn3jHn3iHn3hjn3hDn3gje3oze3nPe3lLe1oze1nPe1lLe1ine'. - '1iHe1hje1hDe1gje1gDW1qXW1mvWzqXWzkLWzhjWzhDWzgjWzg'. - 'DOzrXOzq3OzpzOzgDOxkrOxinOxhjOxhDOxgjOxgDGxqXGxnvG'. - 'xmvGvRjGvRDGvQjGvQDFxbnAvr6/v7+9vaW9vZS9vQi9vQC9tR'. - 'C9tQi9tQC7u7W1tZS1tXu1tTG1tQi1rRC1rQi1rQCtrYytrSGt'. - 'rQitrQCtpYStpSGtpQitpQClpYSlpXulpQClnBClnAilnACcnG'. - 'ucnAicnACclAiclACUlFqUlCmUlAiUlACUjFKUjAiUjACMjFKM'. - 'jEqMjACMhACEhACEewB7ezF7exB7ewB7cwBzcylzcwBzaxBzaw'. - 'BraxhrawhrawBrYxBrYwBjYwBjWgBaWgBaUgCXBwRMAAAAAXRS'. - 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. - 'LdfvwAAAAHdElNRQfTAwkRFBKiJZ4hAAAB7ElEQVR4nI3S+1vS'. - 'UBgHcB67WJmIMWAVdDHEDLBC6Go0slj3Ft0m9RRBWQEmFZFDEM'. - 'Qgt0EMFBY7p/+198hj1kM/9N1+++x73rOd6XT/kStnTx4fPzd9'. - 'uwfOjFhomj7smAhwj/6Cm2O0xUwy6g7cCL99uCW3jtBmE7lsdr'. - 'fvejgpzP7uEDFRRoqy2k8xQPnypo2BUMP6waF9Vpf3ciiSzErL'. - 'XTkPc0zDe3bsHDAcc00yoVgqL3UWN2iENpspff+2vn6D0+NnZ9'. - '6lC5K6RuSqBTZn1O/a3rd7v/MSez+WyIpVFX8GuuCA9SjD4N6B'. - 'oRNTfo5PCAVR0fBXoIuOQzab1XjwwNHx00GOj8/nKtV1DdeArk'. - '24R+0ul9PjmbrHPYl+EipyU0OoQSjg8/m83kl/MMhx0fjCkqio'. - 'SMOE7t4JMAzDsizH81AqSdW2hroLPg4/CEF4PhKNx98vlevrbY'. - 'QQXgV6kXwVfjkTiSXmhYVcSa7DIE1DOENe7GM6lUym0l+EXKks'. - 'K20VAeH2M0JvVgrZfL5Qqkiy0lRVaMBd7H7EZUmsiJJcrTdVja'. - 'wGpdbTLj3/3qwrUOjAfGgg4LnNA5tdQx14Hm00QFBm65hfNzAm'. - '+yIFhFtzuj+z2MI/MQn6Uez5pz4Ua41G7VumB/6RX4zMr1TKBr'. - 'SXAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bl_silver.png - //========================================================== - $this->imgdata_large[3][0]= 1481 ; - $this->imgdata_large[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAADAF'. - 'BMVEUAAADOzs7Gxsa9vb21tbXOxsbOzsbGzsb3///O1ta1vb2c'. - 'paVSWlpKWlpSY2ve5+97hIze7/9aY2vO5/9zhJRaa3tSY3PGzt'. - 'aMlJxrc3tja3NKUlpCSlK1vcZze4RSWmPW5/+Upb3G3v9zhJxS'. - 'Y3t7jKVaa4TO3veltc6ElK1re5Rjc4ycpbV7hJRaY3M5QlLn7/'. - '/Gzt6lrb2EjJzO3v9ja3vG1ve9zu+1xueltdacrc6UpcaMnL1C'. - 'SlqElLV7jK1zhKVre5zW3u/O1ue1vc6ttcaMlKVze4xrc4RSWm'. - 'tKUmPG1v+9zve1xu+tveeltd6crdbe5/+9xt6cpb17hJxaY3s5'. - 'QlrW3vfO1u/Gzue1vdattc6lrcaUnLWMlK2EjKVze5Rrc4xja4'. - 'RSWnNKUmtCSmO9xuecpcZ7hKVaY4TW3v/O1vfGzu+1vd6ttdal'. - 'rc69xu+UnL2MlLWEjK1ze5xrc5R7hK1ja4zO1v+1veettd6lrd'. - 'aMlL3Gzv/39//W1t7Gxs61tb29vcatrbWlpa2cnKWUlJyEhIx7'. - 'e4TW1ufGxta1tcZSUlqcnK3W1u+UlKW9vda1tc57e4ytrcalpb'. - '1ra3vOzu9jY3OUlK29vd6MjKWEhJxaWmtSUmNzc4xKSlpjY3tK'. - 'SmNCQlqUjJzOxs7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. - 'AAAAAAAAAAAAAAAAAAAAAAAAD///9fnkWVAAAAAnRSTlP/AOW3'. - 'MEoAAAABYktHRP+lB/LFAAAACXBIWXMAAABFAAAARQBP+QatAA'. - 'AB/klEQVR42mNgxAsYqCdd3+lcb4hLmj8wMMvEu8DCMqYbU9op'. - 'UEFB2MTb26eyysomFl06XEEhUCHLpAKo2z/fujikEUVaXUFBMB'. - 'BouLePuV+VVWGRciIXknSEsImCQd3//xwmPr65llaFcSFJHkjS'. - '3iYmWUDZ//8NfCr989NjNUMSUyTg0jneSiaCINn/gmlVQM12qg'. - 'lJnp5waTMTE5NAkCyHWZW/lXWNfUlikmdYK0zax7siS4EDKJtd'. - 'mQeU1XRwLBdLkRGASucWmGVnZ4dnhZvn5lmm29iVOWpnJqcuko'. - 'JKR1Wm5eTkRKYF5eblp9sU2ZeUJiV7zbfVg0pH56UFBQXNjIqK'. - 'jgkujItX1koKTVmYajsdKu2qETVhwgSXiUDZ2Bn9xqUeoZ5e0t'. - 'LzYYZ3B092ndjtOnmKTmycW1s7SHa+l5dtB8zlccE6RlN0dGbM'. - 'mDVbd5KupNBcL6+F82XgHouLj5vRP2PWLGNdd4+ppnxe8tJec6'. - 'XnNsKkm0uVQ5RDRHQTPTym68nPlZbvkfYCexsa5rpJ2qXa5Umm'. - 'ocmec3m8vHjmSs+fgxyhC5JDQ8WSPT2lvbzm8vDIe0nbtiBLN8'. - '8BigNdu1B6Lsje+fPbUFMLi5TMfGmvHi/puUAv23q2YCTFNqH5'. - 'MvPnSwPh3HasCbm3XUpv+nS5VtrkEkwAANSTpGHdye9PAAAASn'. - 'RFWHRzaWduYXR1cmUANGJkODkyYmE4MWZhNTk4MTIyNDJjNjUx'. - 'NzZhY2UxMDAzOGFhZjdhZWIyNzliNTM2ZGFmZDlkM2RiNDU3Zm'. - 'NlNT9CliMAAAAASUVORK5CYII=' ; - - //========================================================== - // File: bl_purple.png - //========================================================== - $this->imgdata_large[4][0]= 1149 ; - $this->imgdata_large[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACAV'. - 'BMVEX/////////7///5///1v//xv//rf//pf//lP//jP//hP//'. - 'c///a///Wv//Wvf/Uv//Sv//Qv//Qvf/Off/Mf//Kf//If//If'. - 'f/GP//GPf/EP//EPf/CP//CPf/CO//AP//APf3Oe/3Kff3Ke/3'. - 'Ie/3GO/3EO/3AO/vSu/vSufvOefvMefvIefvGOfvEOfvCOfvAO'. - 'fnUufnSufnMd7nId7nGN7nGNbnEN7nCN7nAN7ejN7ejNbec97e'. - 'c9beUtbeQtbeIdbeGNbeENbeCNbeANbWpdbWa9bWQs7WGM7WEM'. - '7WCM7WAM7Otc7Orc7OnM7OSsbOIb3OGMbOEMbOCMbOAM7OAMbG'. - 'pcbGnMbGe8bGa8bGKbXGEL3GCL3GAL3FucXBu73AvsC/v7+9pb'. - '29Ka29GLW9ELW9CLW9AL29ALW5rrm1lLW1e7W1MbW1GKW1EK21'. - 'CLW1CK21AK2tjK2thKWtMaWtIaWtGJytCK2tCKWtAK2tAKWlhK'. - 'Wle6WlEJylCJylAKWlAJyca5ycGJScEJScCJScAJycAJSUWpSU'. - 'UoyUKZSUEIyUCIyUAJSUAIyMUoyMSoyMIYSMEISMCISMAIyMAI'. - 'SECHuEAISEAHt7MXt7EHt7CHt7AHt7AHNzKXNzEGtzAHNzAGtr'. - 'GGtrEGNrCGtrAGtrAGNjCFpjAGNjAFpaAFpaAFIpZn4bAAAAAX'. - 'RSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsS'. - 'AdLdfvwAAAAHdElNRQfTAwkRFB0ymoOwAAAB9UlEQVR4nGNgIA'. - 'K42hhqGtm5+WFIWClKycvLK6gbuARGoEj4aMjLSElISUir6Tt7'. - 'x+aEIWR8leQlwEBSTc/CK7awLguuR0lGQkJMVFRUTFJVzwko1d'. - 'oFk9OQl5IQE+Dh5hVR0TV3CkkvbJgyASJjDZIR5GBl5eRX0TH1'. - 'DEqrbJ2ypBEspSgvJSXKw8bMxMavbOLoGZNf1TZlybw4oIyfLN'. - 'BxotxsLEzsQiaOHkFpBQ2905esrAZK2SpIAaUEuDm5+LTNPAKj'. - 'C+pbps1evrIDKGWnLictKSkuLKyoZQyUya9o7Z2+YMXKGUApew'. - 'M9PTVdXR0TEwf3wOjUirruafOXL18xFyjl72Kpb25qaurg4REU'. - 'EFVe2zJ5zpLlK1aCpbydnZ2dnDwDA6NTopLLeiZNXbB8BcTAyP'. - 'TQ0JDg4KCY1NS83JKmiVOBepYvX9UPlAovzEiPSU/LLyior2vq'. - 'mjZr3vLlIF01IC+XVhUWFlZW1Lc290ycOGfxohVATSsXx4Oksn'. - 'vaWlsb2tq6J0+bM2/RohVA81asbIcEYueU3t7JU6ZNnwNyGkhm'. - '+cp5CRCppJnzZ8+ZM3/JUogECBbBIixr8Yqly8FCy8F6ltUgoj'. - 'lz7sqVK2ByK+cVMSCDxoUrwWDVysXt8WhJKqG4Y8bcuTP6qrGk'. - 'QwwAABiMu7T4HMi4AAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bl_gray.png - //========================================================== - $this->imgdata_large[5][0]= 905 ; - $this->imgdata_large[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAABO1'. - 'BMVEX////////3///39/fv7+/e5+fW3t7Wzs7WxsbG1tbGzsbG'. - 'xsbDxMS/v7++wMC+v7+9zsa9xsa9vb29tbW9ra29pa24uLi1xs'. - 'a1vb21tbWxtrattbWmpqalra2cra2cpaWcnJycjIyUpaWUnJyU'. - 'lJSUjIyMnJyMnJSMlJSMlIyMjJSMjIyElJSElIyEjIyEhIR7jI'. - 'x7hIR7hHt7e3t7e3N7e2tzhIRze3tze3Nzc3Nre3trc3Nrc2tr'. - 'a2tjc3Njc2tja3Nja2tjY2NjWlpaa2taY2taY2NaY1paWlpaUl'. - 'JSY2NSY1pSWlpSWlJSUlJSUkpKWlpKWlJKUlpKUlJKUkpKSkpK'. - 'SkJCUlJCUkJCSkpCSkJCQkI5Sko5QkI5Qjk5OUI5OTkxQkIxOT'. - 'kxMTkxMTEpMTEhMTEhKSkYISEpy7AFAAAAAXRSTlMAQObYZgAA'. - 'AAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdE'. - 'lNRQfTAwkRFQfW40uLAAABx0lEQVR4nI3SbXfSMBQA4NV3nce5'. - 'TecAHUywRMHSgFuBCFsQUqwBS1OsWQh0GTj//y8wZUzdwQ/efM'. - 'tzcm/uuXdj4z9ic/PR9k4qk1qDnf0X2/uZzKt8GaRvSubg4LVp'. - 'mkWzCGAT/i3Zsm2XNQHLsm2n2937LaaNnGoJFAEo27B50qN0ay'. - 'Wg26lXsw8fP8nmzcJb2CbsnF5JmmCE8ncN404KvLfsYwd7/MdV'. - 'Pdgl/VbKMIzbuwVgVZw2JlSKJTVJ3609vWUY957lgAUd1KNcqr'. - 'yWnOcOPn8q7d5/8PywAqsOOiVDrn42NFk+HQ7dVuXNYeFdBTpN'. - 'nY5JdZl8xI5Y+HXYaTVqEDp1hAnRohZM03EUjMdhn5wghOoNnD'. - 'wSK7KiiDPqEtz+iD4ctdyAifNYzUnScBSxwPd6GLfRURW7Ay5i'. - 'pS5bmrY8348C5vvUI+TLiIVSJrVA0heK/GDkJxYMRoyfCSmk4s'. - 'uWc3yic/oBo4yF374LGQs5Xw0GyQljI8bYmEsxVUoKxa6HMpAT'. - 'vgyhU2mR8uU1pXmsa8ezqb6U4mwWF/5MeY8uLtQ0nmmQ8UWYvb'. - 'EcJaYWar7QhztrO5Wr4Q4hDbAG/4hfTAF2iCiWrCEAAAAASUVO'. - 'RK5CYII=' ; - - //========================================================== - // File: bl_brown.png - //========================================================== - $this->imgdata_large[6][0]= 1053 ; - $this->imgdata_large[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABoV'. - 'BMVEX////Gzs7GvbXGrZTGpXu9nHO1nHO1nIy9taXGxs7GtaXO'. - 'nHPGlFrGjEq9hEq1hEqte0Klczmcazmce1KtnIzGxsbGvb3OlF'. - 'LOlFq9hFKte0qcc0KUYzGEWimMc1K9ta3OnGvOnGPWnGO9jFq9'. - 'jFKlc0KUazmMYzl7UilzUjGtpZzGxr3GnGPWpWvepXO1hFJ7Wj'. - 'FrSiFjUjG1ra3GnHPvxpT/5733zpythFKUa0KEYzlzUilaOSF7'. - 'Wjm9jErvvYz/99b///f/78bnrYS1hFqle0p7UjFrSiljQiFCMR'. - 'iMhHO9lGvGjFLWnGv/3q3////erXuthEqlc0paQiFKMRhSQin/'. - '1qX/997//++cc0pjSilaQilKORhCKRiclIy9pYzGlGPntYT33q'. - '3vvZSEWjlSOSE5KRB7c2O1lHutczmthFqte1JrWkqtjGtCKRBa'. - 'SjmljGuca0KMYzGMaznOztaclISUYzmEWjFKOSF7a1qEYzFaSi'. - 'GUjISEa0pKOSm9vb2llIxaQhg5IQiEc2tzY0paORilnJy1raVS'. - 'OSljUkJjWkKTpvQWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. - 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkREiei'. - 'zP2EAAAB9UlEQVR4nGWS/VfSUBjHL5QluhhBxtwyWcCus5Blpm'. - 'wDC4ONaWXCyBi7RMZmpQ2Bypm9W/byV3cHHo/W88s95/s5z/d5'. - 'uwCcCh/4L3zAf+bs0NC588On9QAYGSUuBINk6GI4cmnsBLk8Go'. - '1SFEGMkzRzZeLq5JE8FvDHouw1lqXiCZJOcnCKnx4AcP0GBqmZ'. - 'mRgRT9MMB4Wbs7cGSXNRik3dnp9fiMUzNCNKgpzN9bsaWaQo9s'. - '7dfH7pXiFTZCBU1JK27LmtBO8TDx7mV1eXHqXXyiIUFLWiVzHx'. - 'BxcJIvV4/cn6wkqmWOOwmVE3UQOAp6HxRKL5bGPj+VwhUhalFq'. - '8alm5vAt+LlySZTsebzcKrraIIW4JqZC3N3ga+1+EQTZKZta1M'. - 'pCZCSeDViqVrThsEdsLJZLJYLpZrHVGScrKBvTQNtQHY6XIM02'. - 'E6Ik7odRW1Dzy3N28n3kGuB3tQagm7UMBFXI/sATAs7L5vdbEs'. - '8Lycm923NB0j5wMe6KOsKIIyxcuqauxbrmlqyEWfPmPy5assY1'. - 'U1SvWKZWom9nK/HfQ3+v2HYZSMStayTNN0PYKqg11P1nWsWq7u'. - '4gJeY8g9PLrddNXRdW8Iryv86I3ja/9s26gvukhDdvUQnIjlKr'. - 'IdZCNH+3Xw779qbG63f//ZOzb6C4+ofdbzERrSAAAAAElFTkSu'. - 'QmCC' ; - - //========================================================== - // File: bl_darkgreen.png - //========================================================== - $this->imgdata_large[7][0]= 1113 ; - $this->imgdata_large[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. - 'BMVEX////////3///v///n/+/e99bW/+/W99bO786/v7++vr69'. - '/96999a7wb24vbu1/9a1zqW1u7itxrWosq6l772l1qWlxrWlxq'. - '2lva2cxpSU562U3q2UxqWUvaWUpZyM77WM57WMvYyMtZyMrZyM'. - 'pZSMnJSEvZyEtYyErZSElIx7zpR7xpx7xpR7vZR7jIRz1pRzxp'. - 'RzjIRrzpRrzoxrxoxrtYRrrYxrrXtrpYRrhHNjzoxjxoxjxoRj'. - 'vYRjtYRjrXtjpXtjlGNje2tazoxazoRaxoxaxoRavYRatYRatX'. - 'tarXtapXNanHNajFpae2tSzoRSxoRSvXtStXtSrXtSrXNSpXNS'. - 'nHNSnGtSlGtSlGNSjGtSjGNKvXtKtXNKrXNKpWtKnGtKlGNKjG'. - 'NKhGNKhFJKc1pKa1JCrWtCpWtCnGtClGNCjGNCjFpChFpCe1JC'. - 'a1JCY1I5pWs5nGM5lGM5jFo5hFo5e1o5c0o5WkoxjFoxhFoxhF'. - 'Ixe1Ixc1Ixc0oxa0ophFIpe0opc0opa0opa0IpY0IpWkIpWjkp'. - 'UkIpUjkhc0oha0IhY0IhWjkhWjEhUjkhUjEhSjEhSikhQjEhQi'. - 'kYWjkYSjEYSikYQjEYQikQSikQQikQQiEQOSExf8saAAAAAXRS'. - 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. - 'LdfvwAAAAHdElNRQfTAwkRFCaDkWqUAAAB+ElEQVR4nI3S+1vS'. - 'UBgHcGZlPV0ks/vFrmQWFimJjiwiYUJWjFBWFhClyZCy5hLrwA'. - 'x2EIwJC1w7zf2vnU0re+iHvs9++7x7zznvORbLf+TA6ct9fYMX'. - 'jrfAUYefpp+/iM1ykxf/lmuhUZ/PTwXC8dml5Wcd23o5H5Mk6b'. - '5NUU8icXbhS67rNzn9JDnguOEYGQtEEtwC+Crs3RJ76P5A/znr'. - 'vsNX7wQnEiwHCtK7TTkW8rvdZ9uJtvZTLkxpHhSrP66bNEj7/P'. - '3WNoLYeeSWQQCIpe9lQw7RNEU5rDsIYtcJ14Nocg7kRUlBNkxn'. - 'YmGKcp7cv3vPwR7XOJPmc0VYU3Sv0e9NOBAYG7Hbz/cMjTMveZ'. - 'CHkqxuTBv0PhYJB4N3XR6PJ5rMAPMnpGUxDX1IxSeMTEaZp1OZ'. - 'nGAIQiYtsalUIhFlmGTy3sO3AizJCKn6DKYryxzHsWyaneMzr6'. - 'cWxRVZVlFTe4SpE3zm+U/4+whyiwJcWVMQNr3XONirVWAklxcE'. - 'EdbqchPhjhVzGpeqhUKhWBQhLElr9fo3pDaQPrw5xOl1CGG1JE'. - 'k1uYEBIVkrb02+o6RItfq6rBhbw/tuINT96766KhuqYpY3UFPF'. - 'BbY/19yZ1XF1U0UNBa9T7rZsz80K0jWk6bpWGW55UzbvTHZ+3t'. - 'vbAv/IT+K1uCmhIrKJAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bl_green.png - //========================================================== - $this->imgdata_large[8][0]= 1484 ; - $this->imgdata_large[8][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMMFjM4kcoDJQAABVlJREFUeNq9ll2MJFUVx3/11V'. - 'Vd/TE9vU0v4zLDwJIF16jBqLAPhsRXEiDqg0QTJiQSjcSNvCzw'. - 'sBEDDxizhvAAxBgf1oR9QF9NiE9ESFZkQyZB5WtddmdnZ3qqqr'. - 'uqbt367Cofqu3ZZpWVaDzJfbkf53//55z/PVdZXV3l/2H6f7Lp'. - '5VdOV/4Nb+GmHpUeA7AdBNxc3kafNb73jRPK9Xwon8ToxVefqU'. - 'b91wibH5EkCQBCizFihTSviHUHR0hWws9xe3wvJ7/7nPKpgX5y'. - '9oFqt3eOgWniRBoAbUBGGqZUibSYaeoT2B5bnkdaSA6793Cv/S'. - 'QPPbihXBfo5VdOV+8dfgnvwAU62YH5fCZ12sDujFkwyegCqTrB'. - 'iUOKTOJKj8jr88jS8zy6cXwBTP048nuHX0I0nDlIp7RpTG7kM0'. - 'sdyAYsTVukUuWGhlWHMq0ITL92lnUp9R1Obz/GmTNnqn9bDD8/'. - '+0D1oX0O0zQZZDYCsK2j3Gl9jQqDfHiei8GfiKVLlsZkJaBAN1'. - '0i6PgwUbB0GxG5/PrtE/xLRr959Znqw9452oVNI+jiJhnr1pe4'. - 'k29zB1/nFr5Kj7tpt1YYhJ0FJ7nUYbcJQBgahN2MzeCP/OipR6'. - 'prgN6Qr6ELFQFUWoRpNVjlKwxZB8DCpE+PtfEKqV1cUzxpVudu'. - 'GTBHA5Y1g99e+dUio9O/P1Vpq+/WE5GGjDSMoAtAQjrf3C52IP'. - 'QxpY4WK2hpReka9Gfrhqgz0bACRoCWjDh56kQ1z9FeuUUQxVhK'. - 'B92sD1VahM+bAJgcoJhGjP/6Ln8rAgDiRCVRKiIzxMkkodBJ85'. - 'im1IlEHbE4k1xyNveL4YP8HarmGJIOpqyjeQmfNHmTvnqZTWBt'. - 'vIJXpPwlukJSuSTKGK3pEwtJmiX00ZlInTyNscImO6XBITvH1c'. - '8vVt2OucdKvIyeKRTNCivsEMgcpg6taYs30nfq0Gqg6hOSSFJ4'. - 'BSnJPht0IqEjWmOGocEI6F0J94F0qaL6BntTF0MtUfweKQKAPU'. - 'Wwp4OcVnQAmVb0p9DLOzjEhEKnGRmoRc7EzRGlwA6NujAKG4yP'. - '6Sjwc4aVznZ7DK0xXdkDoJf0kGmFBniFBOBGcZSCCSKd0IwN0k'. - 'IS+QZWCGVZex4BnUxya3+Zt9iugQbcRFpIAtuHvAZulPUdLhUJ'. - 'RqegI3WcqaSXddlT3idsWMSRRGkEtNwmyTifAwyBo7LP+11J0e'. - '7tM7pZOYblHkBLcqZ5LcYtw6Wbd4CM3SpE9foYZsIHoqDKCrbz'. - 'mLSQtPwmuhXgtBLs0GBdbXOhFGB7WBKO2F8GXt9/VO97Ya3atF'. - '7nUHnwGjGGQqcPxFEdFqURkEidiZszAERoYIsGju1hq21kWee3'. - 'bw15+8WpsvAy3K1+i3JkkhZyPpxxjjPOsfOYiZ+TFhLPzQnHOU'. - 'tpzGB2dgA4tscIkKIx19Cxg/fPL7vQJu47eXt1VvsDK8pwPueZ'. - 'PuZoQMOqhRoJHSs0kKLBWjvjYinmeQGw1TaX1RFdfZ3LMzYLjA'. - 'C++dkn6AaH2Nobk6cxEzdnuG0TdC8zvdJkN0hqkFkO/jwL0fxa'. - 'so8sBcuFzQ+/+MRC+BeAHnpwQzn++ee5KT9Eshuy46dcKAXm32'. - '0uzPQhS4GttkH2GQID2Wc0Y4LtAbDxhZ/x5A+e/uTG9+jGceXH'. - '9/ySnnIXnUzOxXe1038mW3ZynNmam4yYWkO+f9cv+Oljz16/lV'. - '9tDz/9nerc1hm8ZEScSRK7VvtYl1i1dklsOKyvc+zg/bzw1O8+'. - '/efkajt56kR1ydlEJBc5H46xzbrJ3dY9wrB7hGcff+6/+279L+'. - '0fHxyiE8XMLl4AAAAASUVORK5CYII=' ; - - //========================================================== - // File: bl_blue.png - //========================================================== - $this->imgdata_large[9][0]= 1169 ; - $this->imgdata_large[9][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACEF'. - 'BMVEX/////////7//35//v1v/exv/Wvf/Wrf/Wpf/Orf+/v7+9'. - 'tc69jP+9hP+5ucW1tc6tlP+rq7Wlpdalpcalpb2cnM6cnMacc/'. - '+cWv+UlLWUjN6UjK2Uc/+Ma/+MUv+EhKWEa/+EQvd7e8Z7e7V7'. - 'e6V7c957Wv9za9Zza8ZzSv9ra5xrSv9rOf9rMe9jUudjQv9jOe'. - '9aWpRaUt5aUpRaSu9aSudSUoxSSs5SSoxSMf9KQtZKOfdKMedK'. - 'Kf9KKe9CKf9CKb1CKa1CIfdCIedCId45MXs5Kfc5If85Iec5Id'. - 'Y5GP8xMbUxMXsxKc4xKZQxIf8xGP8xGO8xGN4xGNYxGL0xGK0p'. - 'KXMpIYwpGP8pGO8pGOcpGNYpGM4pEP8pEPcpEOcpEN4pENYpEM'. - 'YpEL0hGKUhEP8hEPchEO8hEOchEN4hENYhEM4hEMYhELUhCP8h'. - 'CO8hCN4YGJwYGGsYEL0YEK0YEHMYCN4YCM4YCMYYCL0YCKUYAP'. - '8QEJQQEIwQEHsQEGsQCM4QCLUQCK0QCKUQCJwQCJQQCIwQCHMQ'. - 'CGsQAP8QAPcQAO8QAOcQAN4QANYQAM4QAMYQAL0QALUQAKUQAJ'. - 'QQAIQICGsICGMIAO8IANYIAL0IALUIAK0IAKUIAJwIAJQIAIwI'. - 'AIQIAHsIAHMIAGsIAGMAAN4AAMYAAK0AAJQAAIwAAIQAAHMAAG'. - 'sAAGMAAFrR1dDlAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFRPMOZ'. - '/2AAAB+klEQVR4nGNgIAIIqeqZmBqpi2JISNml5lVXV3d198Yo'. - 'oUjwm1SnxsbGRsSm5ZfNXO4tjCTjVh0ABhFx6QV9E1Y0S8JkuN'. - '3yAgLc7W3t/QPi4jPKJ8ye1yoIlTKpjvVy15eVUbN0i4zKLJ8w'. - 'ae6qcKgLqmMj3PUFWFl5NJ0CExLLJzbNW7BWCyxlXR0ba6/Axs'. - 'zELmfnkRBT0QiSKgXJCOflxUbYy3KyMHEoOrtEZ1c2TZ6/cMl6'. - 'eaCUamdsbIC7tjgPr4SBS3BMMVDTwkXr1hsDpYy6UmMj/O0tdX'. - 'QNbDxjknJLWqYsXLx0vStQynxGflpkZGCgs7Onp29SbtNkoMy6'. - 'pevCgFJWy3oyMuKjgoKCPWNCvEuqWhcsWrJ06XqQlPnMvrKyrM'. - 'TomJjkZAfHlNa2qdOWrlu63gcopbG8v7+hvLwip7g4JdSxsLZu'. - '8dKlS9ettwBKic2eNXHChIkTG5tKqgpr2uo6loLAehWQx0LnzJ'. - '49p6mpeXLLlNq6RUvqly6dvnR9Bx9ISnnlvLmT582bMr9t4aL2'. - '+vrp60GaDCGB6Ld6wfwFCxYCJZYsXQ+SmL6+FBryInVrFi1atH'. - 'jJkqVQsH6pNCzCJNvXrQW6CmQJREYFEc2CYevXrwMLAyXXl0oz'. - 'IAOt0vVQUGSIkabkDV3DwlzNVDAksAAAfUbNQRCwr88AAAAASU'. - 'VORK5CYII=' ; - - //========================================================== - // File: bs_red.png - //========================================================== - $this->imgdata_small[0][0]= 437 ; - $this->imgdata_small[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. - 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. - 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. - 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. - 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. - 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. - 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGDNEMgOYAAAAm0'. - 'lEQVR4nI3Q3RKCIBAFYGZMy9RKzX7MVUAUlQTe/+kS0K49d3wD'. - '7JlFaG+CvIR3FvzPXgpLatxevVVS+Jzv0BDGk/UJwOkQ1ph2g/'. - 'Ct5ACX4wNT1o/zzUoJUFUGBiGfVnDTYGJgmrWy8iKEtp0Bpd2d'. - 'jLGu56MB7f4JOOfDJAwoNwslk/jOUi+Jts6RVNrC1hkhPy50Ef'. - 'u79/ADQMQSGQ8bBywAAAAASUVORK5CYII=' ; - - - //========================================================== - // File: bs_lightblue.png - //========================================================== - $this->imgdata_small[1][0]= 657 ; - $this->imgdata_small[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABVl'. - 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. - 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. - '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. - 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. - 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. - 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. - 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. - 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. - 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. - 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. - 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGTok'. - '9Yp9AAAAtElEQVR4nGNgIBaw8wkpKghzwvksPAKiUsraprYiLF'. - 'ARXkE2JiZ1PXMHXzGIAIekOFBE08TGLTCOCyzCLyvDxsZqZOnk'. - 'E56kAhaRV9NQUjW2tPcMjs9wBYsY6Oobmlk7egRGpxZmgkW0zC'. - '2s7Jy9giKT8gohaiQcnVzc/UNjkrMLCyHmcHr7BYREJKTlFxbm'. - 'QOxiEIuKTUzJKgQCaZibpdOzQfwCOZibGRi4dcJyw3S4iQ4HAL'. - 'qvIlIAMH7YAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bs_gray.png - //========================================================== - $this->imgdata_small[2][0]= 550 ; - $this->imgdata_small[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1'. - 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. - 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. - 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. - 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. - 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. - 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. - '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. - 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. - 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA'. - 'AAsSAdLdfvwAAAAHdElNRQfTAwkUGiIctEHoAAAAfElEQVR4nI'. - '2N2xKDIAwF+bZ2kAa8cNFosBD//yvKWGh9dN+yk9kjxH28R7ze'. - 'wzBOYSX6CaNB927Z9qZ66KTSNmBM7UU9Hx2c5qjmJaWCaV5j4t'. - 'o1ANr40sn5a+x4biElrqHgrXMeac/c1nEpFHG0LSFoo/jO/BeF'. - 'lJnFbT58ayUf0BpA8wAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bs_greenblue.png - //========================================================== - $this->imgdata_small[3][0]= 503 ; - $this->imgdata_small[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAxl'. - 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. - '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. - '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. - 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. - 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. - 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. - 'dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfT'. - 'AwkUGTIqLgJPAAAAqklEQVR4nI2QVxOCMBCEM6Mi2OiCvSslJB'. - 'CUoqjn//9TYgCfubf9Zu9uZxFqO+rscO7b6l/LljMZX29J2pNr'. - 'YjmX4ZaIEs2NeiWO19NNacl8rHAyD4LR6jjw6PMRdTjZE0JOiU'. - 'dDv2ALTlzRvSdCCfAHGCc7yRPSrAQRQOWxKc3C/IUjBlDdUcM8'. - '97vFGwBY9QsZGBc/A4DWZNbeXIPWZEZI0c2lqSute/gCO9MXGY'. - '4/IOkAAAAASUVORK5CYII=' ; - - //========================================================== - // File: bs_yellow.png - //========================================================== - $this->imgdata_small[4][0]= 507 ; - $this->imgdata_small[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAzF'. - 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. - 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. - 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. - 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. - 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. - '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. - 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAH'. - 'dElNRQfTAwkUGSDZl3MHAAAAqElEQVR4nI3QWRNDMBAA4My09E'. - 'IF1SME0VT1okXvM/3//6kEfbZv+81eswA0DfHxRpOV+M+zkDGG'. - 'rL63zCoJ2ef2RLZDIqNqYexyvFrY9ePkxGWdpvfzC7tEGtIRly'. - 'nqzboFKMlizAXbNnZyiFUKAy4bZ+B6W0lRaQDLmg4h/k7eFwDL'. - 'OWIky8qhXUBQ7gKGmsxpC+ah1TdriwByqG8GQNDNr6kLjf/wAx'. - 'KgEq+FpPbfAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bs_darkgray.png - //========================================================== - $this->imgdata_small[5][0]= 611 ; - $this->imgdata_small[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABJl'. - 'BMVEX////////o8v/f6O7W4OnR3PXL1OTL0evEyLvCzePAwMC/'. - 'v7a8wsq7t7C1xum1vtS1q6GzopmyxeKsrsOqvNWoq7anvN+nsb'. - 'qhrcGgqbGfpq6cp7+bqMuVmJKRm7yPlKKMnL6FkKWFipOEkLSE'. - 'j6qEhoqAiaB+jqd8haF7hZR4iJt4g5l3hZl2gIt2cod1hJVzeY'. - 'VzboJvhp9sfJJsb41peY1pd5xpdoVod4xndI5lcHxka4BjcYVg'. - 'Z3BfboFbb4lbZnZbYntaZ4laZYVZV3JYYWpXX3JWWm5VX4RVW2'. - 'NUYX9SXHxPWn5OVFxNWWtNVXVMVWFKV3xHUGZGU3dGTldFSlxE'. - 'Sk9ESXBCRlNBS3k/SGs/RU4+R1k9R2U6RFU2PUg0PEQxNU0ECL'. - 'QWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAA'. - 'CxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGQmbJetrAAAAtklEQV'. - 'R4nGNgwAK4JZTNNOWlYDxhMT4ZDTOzQE1uMF9CiJWVU0LbxDlS'. - 'G8QVF+FnZ2KRNHAIiPUHaZGSlmZj5lH19A1KjLUA8lXU5MWllF'. - 'yjo30TYr2BfG19G11b37CEeN84H38gX1HbwTUkOjo+zjfG3hLI'. - 'l1exCvCNCwnxjfMz0gTyRdXNHXx9fUNCQu2MwU6SN3ZwD42LCH'. - 'W30IK4T8vUJSAkNMhDiwPqYiktXWN9JZj7UQAAjWEfhlG+kScA'. - 'AAAASUVORK5CYII=' ; - - - //========================================================== - // File: bs_darkgreen.png - //========================================================== - $this->imgdata_small[6][0]= 666 ; - $this->imgdata_small[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABX1'. - 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. - 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. - 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. - 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. - '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. - 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. - 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. - 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. - 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. - 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. - 'RQfTAwkUGRjxlcuZAAAAtElEQVR4nGNgIBZw8osqqIpzw/msfI'. - 'IiUmr6lo6SbFARASEOJiYtQ2uXADmIAJeEGFBE18LBMySBBywi'. - 'LC/LwcFiZuvmH5WiAxZR0tRW1DC3dfYJS8zyAouYGBibWtm7+o'. - 'TEpZfkgEX0rG3snNx9Q2NSCksgaqRd3Ty8gyLiU/NKSiDmcPsF'. - 'BodHJ2UUlZTkQ+xikIlNSE7LLgECZagL2VQyc0H8YnV2uD94jS'. - 'ILIo14iQ4HALarJBNwbJVNAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bs_purple.png - //========================================================== - $this->imgdata_small[7][0]= 447 ; - $this->imgdata_small[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAnF'. - 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. - 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. - 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. - 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. - 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. - 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGS'. - 'o5QpoZAAAAnElEQVR4nI3Q2xJDMBAG4MyQokWrZz3oSkJISJH3'. - 'f7dK0Gv/Xb7J7vyzCK0NjtPsHuH/2wlhTE7LnTNLCO/TFQjjIp'. - 'hHAA6bY06LSqppMAY47x+04HXTba2kAFlmQKr+YuVDCGUG2k6/'. - 'rNwYK8rKwKCnPxHnVS0aA3rag4UQslUGhrlk0Kpv1+sx3tLZ6w'. - 'dtYemMkOsnz8R3V9/hB87DEu2Wos5+AAAAAElFTkSuQmCC' ; - - - //========================================================== - // File: bs_brown.png - //========================================================== - $this->imgdata_small[8][0]= 677 ; - $this->imgdata_small[8][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABaF'. - 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. - 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. - 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. - 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. - '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. - 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. - 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. - 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. - 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. - 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. - 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLd'. - 'fvwAAAAHdElNRQfTAwkUGho0tvl2AAAAtklEQVR4nGNgIBaoSg'. - 'mLKGpowfkGMty8AqJKpi4mRlAROR5ONg4JFUv3YHOIgDo/HwsT'. - 'q6yps29EsjZYREFIkJ2ZS9/OMzA20wEsIi8uKSZtaOPmH5WSFw'. - 'YW0VRW07Vw8vCLSMguLwCL6FlaObp6B0TGZxSXQ9TouHv6+IXG'. - 'JGYWlpdDzNEKCgmPjkvLKS0vL4LYxWAen5SelV8OBNZQFxrZ5h'. - 'aC+GX2MDczMBh7pZakehkTHQ4AA0Am/jsB5gkAAAAASUVORK5C'. - 'YII=' ; - - //========================================================== - // File: bs_blue.png - //========================================================== - $this->imgdata_small[9][0]= 436 ; - $this->imgdata_small[9][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. - 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. - 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. - 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. - 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. - 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. - 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGhNNakHSAAAAmk'. - 'lEQVR4nI3P2xKCIBAGYGfM6SBWo1nauIqogaDA+z9dK9Lhrv47'. - 'vtl/2A2CfxNlJRRp9IETYGraJeEb7ocLNKznia8A7Db7umWDUG'. - 'sxAzhurxRHxok4KQGqCuEhlL45oU1D2w5BztY4KRhj/bCAsetM'. - '2uObjwvY8/oX50JItYDxSyZSTrO2mNhvGMbaWAevnbFIcpuTr7'. - 't+5AkyfBIKSJHdSQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bs_green.png - //========================================================== - $this->imgdata_small[10][0]= 452 ; - $this->imgdata_small[10][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAn1'. - 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. - '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. - 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. - '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. - 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. - 'AIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAw'. - 'kUGgW5vvSDAAAAnklEQVR4nI3QSxKCMAwA0M4gqCgoiiJ+kEAL'. - 'LQUq0PufzX7ENdnlJZNkgtDS2CYZvK6bf+7EoKLA9cH5SQzv6A'. - 'YloTywsAbYr44FrlgrXCMJwHl3xxVtuuFkJAPIcw2tGB9GcFli'. - 'oqEf5GTkSUhVMw2TtD0XSlnDOw3SznE5520vNEi7CwW9+Ayjyq'. - 'U/3+yPuq5gvhkhL0xlGnqL//AFf14UIh4mkEkAAAAASUVORK5C'. - 'YII=' ; - - - //========================================================== - // File: bs_white.png - //========================================================== - $this->imgdata_small[11][0]= 480 ; - $this->imgdata_small[11][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMLFTsY/ewvBQAAAW1JREFUeJytkz2u4jAUhT/jic'. - 'gfBUKiZhE0bIKeVbCWrIKenp6eDiGlCEEEBArIxvzGU4xeZjLk'. - 'jWb05lRXuvbx+exr4bouX1Xjyw7Atz81F4uFBYjjGIDhcCjq1o'. - 'k6nN1uZwFerxfP55Msy1itVmRZBsB4PK6YveHkeW5d18XzPIIg'. - 'wPd9Wq0WnU6HMAxJkoQoiuynOIfDwUopkVIihKAoCgAcx6Hdbm'. - 'OMIU1T5vN55eBKEikljUYDIX6kFUKU9e8aDAZlmjcca+1b7TgO'. - '1+uVy+VS9nzfr8e53++VzdZaiqIgz3OMMWitOZ/PaK0JgqDeRC'. - 'mF53lIKYGfr3O73TDGoJQiTVO01nS73XqT4/FIs9kkCAIej0eZ'. - 'brPZEMcxSZKgtQZgMpmIWpN+vy+m06n1PK9yTx8Gy+WS/X5Pr9'. - 'er9GuHLYoiG4YhSilOpxPr9Zrtdlti/JriU5MPjUYjq7UuEWaz'. - '2d+P/b/qv/zi75oetJcv7QQXAAAAAElFTkSuQmCC' ; - - - //========================================================== - // File: bs_cyan.png - //========================================================== - $this->imgdata_small[12][0]= 633 ; - $this->imgdata_small[12][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABPl'. - 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. - '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. - 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. - '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. - 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. - '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. - '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. - 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. - 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. - 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. - 'AHdElNRQfTAwkUGQDi+VPPAAAAtElEQVR4nGNgIBawikipyIiy'. - 'wfksfJpGRkamNtr8LFARPiMFHmFDcztXfwGoFi0jLiZuZRtnry'. - 'BddrCIiJEGL6eklYO7X3iCOFhE2thESdHawdUnJDZFDiyiamZh'. - 'aevk5h0UlZSpBhaRtbN3dPHwDY5MSM+EqBFzc/f0DgiLTkjLzI'. - 'SYw6bjHxgaEZeckZmpD7GLQSAqJj4xNRMIBGFuFtRLA/ENhGBu'. - 'ZmDgkJBXl5fgIDocAAKcINaFePT4AAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bs_bluegreen.png - //========================================================== - $this->imgdata_small[13][0]= 493 ; - $this->imgdata_small[13][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAvV'. - 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. - 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. - '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. - 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. - '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. - 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. - 'AJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGxNUcXCT'. - 'AAAAqUlEQVR4nI2Q1xKCMBREM2NHLCCogAGCjd6SqLT8/2cZKT'. - '6zb3tm987OBWCsXoejp8rC35fi4+l6gXFZlD0Rz6fZ1tdDmKR9'. - 'RdOmkzmP7DDpilfX3SzvRgQ/Vr1uiZplfsCBiVf03RJd140wgj'. - 'kmNqMtuYXcxyYmNWJdRoYwzpM9qRvGujuCmSR7q7ARY00/MiWk'. - 'sCnjkobNEm1+HknDZgAqR0GKU43+wxdu2hYzbsHU6AAAAABJRU'. - '5ErkJggg==' ; - - //========================================================== - // File: bs_lightred.png - //========================================================== - $this->imgdata_small[14][0]= 532 ; - $this->imgdata_small[14][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAA3l'. - 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. - 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. - 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. - 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. - 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. - 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. - 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. - 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGjoP2Nm+AAAAr0'. - 'lEQVR4nGNgIBaYiOk62imYwPnMkiIyso76yhJSzFARMxkRNk49'. - 'a3t5OW6oFk1LVkYOfWUHKxUXiEYzLS12DnN3VXkjIRtFsIiSk5'. - '6evqGqhYGKugAfWMRa1FpD2UHeQEXQRlgALCJur+rgbCUNFOAS'. - 'hqjRkZe3MpBTcwEKCEPMMTGSs3Xz8OQHCnBBHckt6OJpIyAMBD'. - 'wwN/MYc4H4LK4wNzMwmGrzcvFqmxIdDgDiHRT6VVQkrAAAAABJ'. - 'RU5ErkJggg==' ; - - //========================================================== - // File: bxs_lightred.png - //========================================================== - $this->imgdata_xsmall[0][0]= 432 ; - $this->imgdata_xsmall[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAA3l'. - 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. - 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. - 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. - 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. - 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. - 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. - 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. - 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKBOgGhWjAAAAS0'. - 'lEQVR4nGNgQAEmunYmEJaMCKe1vBxYzJKVQ9lKBSSupKdnaKGi'. - 'zgdkiqs6WKnYcIGYJnK2HvzCwmCNgi42wsLCECNMeXlNUY0HAL'. - 'DaB7Du8MiEAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bxs_bluegreen.png - //========================================================== - $this->imgdata_xsmall[1][0]= 397 ; - $this->imgdata_xsmall[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAvV'. - 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. - 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. - '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. - 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. - '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. - 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. - 'AJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKDVyF5Be'. - 'AAAASUlEQVR4nGNgQAFmYqJcEJaEOJ+UrD5YTJKFTZrfGCQuaq'. - 'glLWvMaQ5kqujo6hnbKIKYXPr68gp2dmCNJiZAlh3ECGsREWtU'. - '4wF1kwdpAHfnSwAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bxs_navy.png - //========================================================== - $this->imgdata_xsmall[2][0]= 353 ; - $this->imgdata_xsmall[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. - 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. - 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. - 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. - 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. - 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. - 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJxXO4axZAAAAR0'. - 'lEQVR4nGNgQAGskhKsEJaslIi8ijpYTJaDU1FVAyQuKSujoKKh'. - 'LQ5kSigpqWro6oOYrOoaWroGBmCNWiCWAdQwUVFWVOMBOp4GCJ'. - 's5S60AAAAASUVORK5CYII=' ; - - //========================================================== - // File: bxs_gray.png - //========================================================== - $this->imgdata_xsmall[3][0]= 492 ; - $this->imgdata_xsmall[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABI1'. - 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. - 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. - 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. - 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. - 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. - 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. - '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. - 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. - 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEA'. - 'AAsRAX9kX5EAAAAHdElNRQfTAwkUKC74clmyAAAAQklEQVR4nG'. - 'NgQAVBYVCGt5dXYEQ0mOnp5h4QFgVmeri6+4dHxYMVeHoFRUTH'. - 'gTUFBIZBWAwMkZEx8bFQM2Lj0UwHANc/DV6yq/BiAAAAAElFTk'. - 'SuQmCC' ; - - //========================================================== - // File: bxs_graypurple.png - //========================================================== - $this->imgdata_xsmall[4][0]= 542 ; - $this->imgdata_xsmall[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABSl'. - 'BMVEX////////11P/MqdvKrNfAwMC+u7+9u7+4rr24lsi3rby3'. - 'lMe1rLq1o720q7i0oL20ksSzoryyqbaykMGxlb2wkL+vnbiujb'. - '2sjLuri7qpl7GoirWoibenmK2mla6mjLKmhrSllauki7CjhrCj'. - 'hLGihLChg6+ggq2fkqadkKOcfqqai6Gag6WYe6WXeqSWeaOTd6'. - 'CTd5+Rdp6RdZ6RdZ2Qg5eOc5qMcpiLcZeJb5WIbpOHbZKGbJGE'. - 'a4+CaY2AZ4t/Z4p/Zop/Zol+Zol7ZIZ6Y4V5YoR1ZH11X391Xn'. - '9zXX1yXXtxXHtvWnluWXhsV3VqVnNpVXJoVHFnU3BmUm9jUGth'. - 'VGdgTmheTGZcS2RcSmRaSWJYR19XRl5SQllRQlhQQVdPQFZOP1'. - 'VLPlFJO09IPE5IOk5FOEtEN0lDOEpDOElDNklCNkc/M0XhbrfD'. - 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. - 'EAAAsRAX9kX5EAAAAHdElNRQfTAwkUKCgREfyHAAAATUlEQVR4'. - 'nGNgQAEcIko8EBY3M5Ougy+IxSXMwmTsFsAHZMqrSRvZB0W7A5'. - 'k6FlYugXEZICaPr394Um4uSAFDRFRCbm4uxAihsDAhVOMBHT0L'. - 'hkeRpo8AAAAASUVORK5CYII=' ; - - //========================================================== - // File: bxs_red.png - //========================================================== - $this->imgdata_xsmall[5][0]= 357 ; - $this->imgdata_xsmall[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. - 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. - 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. - 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. - 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. - 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. - 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIyjy5SVMAAAAS0'. - 'lEQVR4nGNgQAFsUpJsEJastIi8ijpYTJaDU0FVgxXIlJKVUVDR'. - '0BYHMiUUlVQ1dPVBTDZ1dS1dAwOQAgYtbSDLAGIEq6goK6rxAD'. - 'yXBg73lwGUAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: bxs_yellow.png - //========================================================== - $this->imgdata_xsmall[6][0]= 414 ; - $this->imgdata_xsmall[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAzF'. - 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. - 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. - 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. - 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. - 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. - '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. - 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAH'. - 'dElNRQfTAwkUIzoBXFQEAAAAS0lEQVR4nGNgQAFsDhJsEJaTo5'. - '2skj5YzMnSSk7ZwBzIlOSUklPiMxYHMnW4FXT5VNVBTDZeXiNV'. - 'QUGQAgYBYyBLEGIEq5gYK6rxAH4kBmHBaMQQAAAAAElFTkSuQm'. - 'CC' ; - - //========================================================== - // File: bxs_greenblue.png - //========================================================== - $this->imgdata_xsmall[7][0]= 410 ; - $this->imgdata_xsmall[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAxl'. - 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. - '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. - '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. - 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. - 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. - 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. - 'dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfT'. - 'AwkUJy5/6kV9AAAATUlEQVR4nGNgQAGCyuyCEJaGugKHviVYzF'. - 'hO3sxCWwDIVNLTM9PXtpEGMhW12Cy0DR1ATEFLSxZ7BweQAgYd'. - 'HUMHBweIEQKiogKoxgMAo/4H5AfSehsAAAAASUVORK5CYII=' ; - - //========================================================== - // File: bxs_purple.png - //========================================================== - $this->imgdata_xsmall[8][0]= 364 ; - $this->imgdata_xsmall[8][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAnF'. - 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. - 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. - 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. - 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. - 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. - 'HUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIj'. - 'mBTjT/AAAASUlEQVR4nGNgQAGskhKsEJaCrJiSuhZYTEFASFlD'. - 'GyQuqSCnrK6tJwpkiquoamgbGIGYrFpaugbGxmCNunpAljHECB'. - 'ZBQRZU4wFSMAZsXeM71AAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bxs_green.png - //========================================================== - $this->imgdata_xsmall[9][0]= 370 ; - $this->imgdata_xsmall[9][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAn1'. - 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. - '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. - 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. - '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. - 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. - 'AIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAw'. - 'kUKBrZxq0HAAAATElEQVR4nGNgQAGccrIcEJaivISyhjaIxa7I'. - 'I6CiqcMKZMopKqho6OhLA5kyqmqaOobGICartraeoYkJSAGDnj'. - '6QZQIxgk1Skg3VeABlVgbItqEBUwAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bxs_darkgreen.png - //========================================================== - $this->imgdata_xsmall[10][0]= 563 ; - $this->imgdata_xsmall[10][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABX1'. - 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. - 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. - 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. - 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. - '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. - 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. - 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. - 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. - 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. - 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. - 'RQfTAwkUKCFozUQjAAAATUlEQVR4nGNgQAGcoqrcEJYQB5OhSw'. - 'CIxSXGwWThGcIDZCppK5o7hyV6AZl6NnbuoSmFICZ3YHB0RkkJ'. - 'SAFDbEJaSUkJxAjeyEheVOMBQj4MOEkWew4AAAAASUVORK5CYI'. - 'I=' ; - - //========================================================== - // File: bxs_cyan.png - //========================================================== - $this->imgdata_xsmall[11][0]= 530 ; - $this->imgdata_xsmall[11][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABPl'. - 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. - '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. - 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. - '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. - 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. - '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. - '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. - 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. - 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. - 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAA'. - 'AHdElNRQfTAwkUKQFKuFWqAAAATUlEQVR4nGNgQAGsUjJsEJaR'. - 'grC5qz9YzIiL28YriB3IlDZRsnYNiZUDMmXtHT2CE9JBTDb/wI'. - 'jkzEyQAoaomMTMzEyIERzy8hyoxgMAN2MLVPW0f4gAAAAASUVO'. - 'RK5CYII=' ; - - //========================================================== - // File: bxs_orange.png - //========================================================== - $this->imgdata_xsmall[12][0]= 572 ; - $this->imgdata_xsmall[12][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABaF'. - 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. - 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. - 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. - 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. - '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. - 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. - 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. - 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. - 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. - 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. - 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9k'. - 'X5EAAAAHdElNRQfTAwkUJBSSy88MAAAATUlEQVR4nGNgQAGqwo'. - 'paEBYPJ4eKezCIpc7HwmrqG6ENZMpLihm6RaWEAZl6Vo7ekRnF'. - 'IKZWSHhcTnk5SAFDfFJWeXk5xAjj1FRjVOMBeFwNcWYSLjsAAA'. - 'AASUVORK5CYII=' ; - - //========================================================== - // File: bxs_lightblue.png - //========================================================== - $this->imgdata_xsmall[13][0]= 554 ; - $this->imgdata_xsmall[13][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABVl'. - 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. - 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. - '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. - 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. - 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. - 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. - 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. - 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. - 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. - 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. - 'gAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJziL'. - 'PvAsAAAATUlEQVR4nGNgQAHsQgqcEJYgG5Oegy+IxSHOxmTiFs'. - 'gFZMprKBnbB8e7AplaFlbOQUl5ICanX0BEWmEhSAFDVGxKYWEh'. - 'xAjusDBuVOMBJO8LrFHRAykAAAAASUVORK5CYII=' ; - - //========================================================== - // File: bxs_darkgray.png - //========================================================== - $this->imgdata_xsmall[14][0]= 574 ; - $this->imgdata_xsmall[14][1]= - 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABm'. - 'JLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAB'. - 'iElEQVR42k3QPU8TYRwA8P//ebkXrgdIColXRAOEkJqbaExMut'. - 'DBhE1GNjYHPg+DG6ODiU6QOLjVxITBcFKBYCstlAC2Bz17fe76'. - 'vLD6+wg/1FpTRFR5lpaub/u1eGBGaAT4HneD4OlXx7avtDYUjT'. - 'HQabd2Ti8e3vVSKzxrtHS32wIpFVldno22Nqvvg2Bhl0gp/aNm'. - 'vJ3qqXAtLIva+ks1H0wqlSXi4+d6+OFTfRsAfHJx2d1od24rZP'. - 'xP2HzopINr1mkesX7ccojqif0v9crxWXODZTno3+dNGA7uWLsd'. - 'mUYU4fHJCViMG9umLBmM4L6fagZGg9QKfjZ+Qfy3C3G/B3mugF'. - 'IHHNcDf64E3KJALApk2p8CSolUUqLjFkyxOGMsTtFyJ+Wz57NQ'. - '8DghS4sLB0svioeZZo7nPhFoUKZDIVFbglkTTnl5/rC8snjAkJ'. - 'Bk/XV5LxHC/v7tR8jzTFPbg8LENK9WX0Vv31T2AEmCSmlKCCoh'. - 'ROnP1U1tPFYjJBRcbtzSf+GPsFTAQBq1n4AAAABKdEVYdHNpZ2'. - '5hdHVyZQBiYzYyMDIyNjgwYThjODMyMmUxNjk0NWUzZjljOGFh'. - 'N2VmZWFhMjA4OTE2ZjkwOTdhZWE1MzYyMjk0MWRkM2I5EqaPDA'. - 'AAAABJRU5ErkJggg==' ; - } -} - + 'imgdata_large', + MARK_IMG_MBALL => 'imgdata_small', + MARK_IMG_SBALL => 'imgdata_xsmall', + MARK_IMG_BALL => 'imgdata_xsmall'); + protected $colors,$index,$maxidx; + private $colors_1 = array('blue','lightblue','brown','darkgreen', + 'green','purple','red','gray','yellow','silver','gray'); + private $index_1 = array('blue'=>9,'lightblue'=>1,'brown'=>6,'darkgreen'=>7, + 'green'=>8,'purple'=>4,'red'=>0,'gray'=>5,'silver'=>3,'yellow'=>2); + private $maxidx_1 = 9 ; + + private $colors_2 = array('blue','bluegreen','brown','cyan', + 'darkgray','greengray','gray','green', + 'greenblue','lightblue','lightred', + 'purple','red','white','yellow'); + + + private $index_2 = array('blue'=>9,'bluegreen'=>13,'brown'=>8,'cyan'=>12, + 'darkgray'=>5,'greengray'=>6,'gray'=>2,'green'=>10, + 'greenblue'=>3,'lightblue'=>1,'lightred'=>14, + 'purple'=>7,'red'=>0,'white'=>11,'yellow'=>4); + + private $maxidx_2 = 14 ; + + + private $colors_3 = array('bluegreen','cyan','darkgray','greengray', + 'gray','graypurple','green','greenblue','lightblue', + 'lightred','navy','orange','purple','red','yellow'); + + private $index_3 = array('bluegreen'=>1,'cyan'=>11,'darkgray'=>14,'greengray'=>10, + 'gray'=>3,'graypurple'=>4,'green'=>9,'greenblue'=>7, + 'lightblue'=>13,'lightred'=>0,'navy'=>2,'orange'=>12, + 'purple'=>8,'red'=>5,'yellow'=>6); + private $maxidx_3 = 14 ; + + protected $imgdata_large, $imgdata_small, $imgdata_xsmall ; + + + function GetImg($aMark,$aIdx) { + switch( $aMark ) { + case MARK_IMG_SBALL: + case MARK_IMG_BALL: + $this->colors = $this->colors_3; + $this->index = $this->index_3 ; + $this->maxidx = $this->maxidx_3 ; + break; + case MARK_IMG_MBALL: + $this->colors = $this->colors_2; + $this->index = $this->index_2 ; + $this->maxidx = $this->maxidx_2 ; + break; + default: + $this->colors = $this->colors_1; + $this->index = $this->index_1 ; + $this->maxidx = $this->maxidx_1 ; + break; + } + return parent::GetImg($aMark,$aIdx); + } + + function __construct() { + + //========================================================== + // File: bl_red.png + //========================================================== + $this->imgdata_large[0][0]= 1072 ; + $this->imgdata_large[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAByF'. + 'BMVEX/////////xsb/vb3/lIz/hIT/e3v/c3P/c2v/a2v/Y2P/'. + 'UlL/Skr/SkL/Qjn/MTH/MSn/KSn/ISH/IRj/GBj/GBD/EBD/EA'. + 'j/CAj/CAD/AAD3QkL3MTH3KSn3KSH3GBj3EBD3CAj3AAD1zMzv'. + 'QkLvISHvIRjvGBjvEBDvEAjvAADnUlLnSkrnMTnnKSnnIRjnGB'. + 'DnEBDnCAjnAADec3PeSkreISHeGBjeGBDeEAjWhITWa2vWUlLW'. + 'SkrWISnWGBjWEBDWEAjWCAjWAADOnp7Oa2vOGCHOGBjOGBDOEB'. + 'DOCAjOAADJrq7Gt7fGGBjGEBDGCAjGAADEpKS/v7+9QkK9GBC9'. + 'EBC9CAi9AAC1e3u1a2u1Skq1KSm1EBC1CAi1AACtEBCtCBCtCA'. + 'itAACngYGlCAilAACghIScOTmcCAicAACYgYGUGAiUCAiUAAiU'. + 'AACMKSmMEACMAACEa2uEGAiEAAB7GBh7CAB7AABzOTlzGBBzCA'. + 'BzAABrSkprOTlrGBhrAABjOTljAABaQkJaOTlaCABaAABSKSlS'. + 'GBhSAABKKSlKGBhKAABCGBhCCABCAAA5CAA5AAAxCAAxAAApCA'. + 'ApAAAhAAAYAACc9eRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFD'. + 'UHLytKAAAB4UlEQVR4nGNgIAK4mGjrmNq6BmFIWMmISUpKSmk5'. + 'B8ZEokj4qoiLiQCBgqald3xaBpKMj6y4sLCQkJCIvIaFV0RaUR'. + 'lCSk5cWEiAn19ASN7QwisuraihHiajKyEixM/NwckjoKrvEACU'. + 'qumpg7pAUlREiJdNmZmLT9/cMzwps7Smc3I2WEpGUkxYkJuFiY'. + 'lTxszePzY1v7Shc2oX2D+K4iLCgjzsrOw8embuYUmZeTVtPVOn'. + 'gqSslYAOF+Ln4ZHWtXMPTcjMrWno7J82rRgoZWOsqaCgrqaqqm'. + 'fn5peQmlsK1DR52vRaoFSIs5GRoYG5ub27n19CYm5pdVPnxKnT'. + 'pjWDpLydnZwcHTz8QxMSEnJLgDL9U6dNnQ6Sio4PDAgICA+PTU'. + 'zNzSkph8hADIxKS46Pj0tKTc3MLSksqWrtmQySAjuDIT8rKy0r'. + 'Kz+vtLSmur6jb9JUIJgGdjxDQUVRUVFpaUVNQ1NrZ9+kKVOmTZ'. + 'k6vR0sldJUAwQNTU2dnX0TgOJTQLrSIYFY2dPW1NbW2TNxwtQp'. + 'U6ZMmjJt2rRGWNB3TO7vnzh5MsgSoB6gy7sREdY7bRrQEDAGOb'. + 'wXOQW0TJsOEpwClmxBTTbZ7UDVIPkp7dkYaYqhuLa5trYYUxwL'. + 'AADzm6uekAAcXAAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bl_bluegreen.png + //========================================================== + $this->imgdata_large[1][0]= 1368 ; + $this->imgdata_large[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMMFi8hE9b2uAAABOVJREFUeNq9lk2sJFUVx3+3qv'. + 'tW95t57zFvhiFxmCFRUJRoNCQiJARMhiFx/Igxii5goTG6ZDAu'. + '/EhcSCIrTAgLEiKsJ8ywABNZEMJXEDYCukAmjgjzBkK/j35V1d'. + '333FtV97io97pfzwxfG86qcu/N+Z3zP+fcW/Apmfk4hx57+R/6'. + 'Rqmc9ykhsWjlsUngAA1fXIQ7b73pI/186IGHnn9dH/8frC8v4I'. + 'PiG53uaerR4GmKkv31mB8cyfjd946ZTwR66qVX9OTWIi8UKUv9'. + 'BOrZXpYZvFeiBvzI0fgSUSFKwbVG+Pl1V3HH0VvNR4KeeukV/f'. + 'PmMmdHhst76aXD64AbeVQ9bjNHaiGOC2o3wLrAb2/4LL/84ffn'. + 'fCdzkOdayKpLppBemrBsU5Y1Zdmm9LJdGU6E/t4M24Q26jRDRL'. + 'j3mdc49cSTekFsMzs5XuTsyLDUNSDQ25NwKOly9YIl22MYhJr/'. + 'uoDtBBoT0CxBRGYOAhibIaOCe//2MpfM6KHnX9cXipSlbkKWmS'. + 'nk9iv38J0jixw7vJfrTMYBOvhSoQHJBS09ANELloAGDxW8tfoW'. + 'J+5/UC8CPS0LU7r3SpYarr7M8rmFjMPLXT6/33L4si7Z2GCrQC'. + '+0ctlOaNs9DReV8vSLr85ndPLpZ/WNvHW+01kAVFBOGvJx0wYg'. + 'Sp47RIQ4Emwa8FGJXlDxSCFo5YlVgAo2hwPue/hRndboTV3EW2'. + 'Wp3k6wBp8q56QiWzecW6vwQfnPRkAWhFgILnq08jQ+R2nlUzzN'. + 'uES9Q7Vd+9fba7NmWJW61db2247qACmcjxXr45psYphsFGSLBu'. + 'kIajxqtjNwHkvAjQt0sg3crhPA2+fPz0CuyNFOghsGsr19mnFg'. + 'DGwrRm8UoAtNmQPQtRXDgdC4HImCFEKcCE0oieUWUYq2LtbiGp'. + 'mBQmppfIkjw45DK0QNNkvQ0jMBtPL0UnDRM1rN+cxKwzvOo2NP'. + 'tykR9a1kfpZNDLMG6QDYJqCTBvUe1+uxs+YKyPoGrTwY2HhvC4'. + 'CDWQd5d4xNApNQEEMgjgLdUCLBQ5cprL/trwNwKG2IUmDqDFd5'. + 'sr5BWrlxuSdLDFEFlqAzXGc4zFjupqh6uqYihpxJcEgp026l2w'. + '7wFUv7Z6AvrfRo/n0OYzPwIKE3HUKAJg2otMBiElnsF7wngis9'. + '3ZDjNnLi7huCWUZfueZKTu/M0V3HvmkOFDVxVKDG04ScejSgW5'. + 'V0q5JYFEghuDLHlTmToqDeGOCKIVtrW9hsdmXufEcNLPSXuPHa'. + 'a+bvuh9df5AH/v5PDFmbWQC3Mx+TVvfGVTRB2CodNgT2JBX003'. + 'aANZAYS/BxCv32TV/l2C03G7jgmfjGiT/qmeEmibEYm7XzAO2k'. + 'A+pbgHhBgydqu54YO5eRiLCy7yDvPP6Xqf+5Z+Lu277OYuOpiw'. + 'H15oBmlNOMcmK5RbP+PrEscGU+DSAxdg4CICIkxnLP8aNz63Og'. + 'H3/rdvOb795GVhuaYo0oBc3GGrEsUPVTwO6a7LYd+X51x3Hu/t'. + 'lP5tS65FN+6okn9U+n/sqb596dTvhOF+02myXTmkQNrOw7yD3H'. + 'j14E+UDQjp24/0E9/eKrbA4HH3aMK1b2ccvXvswjv//1J/s5ud'. + 'Due/hRPfP+OmfOrk7vrn7a48ihA3zh8CH+8Iuffiw/n4r9H1ZZ'. + '0zz7G56hAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_yellow.png + //========================================================== + $this->imgdata_large[2][0]= 1101 ; + $this->imgdata_large[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. + 'BMVEX//////////+///+f//9b//8b//73//7X//63//6X//5T/'. + '/4z//4T//3P//2v//1r//0r//0L//zH//yn//yH//xj//xD//w'. + 'j//wD/90L/9zn/9zH/9xj/9xD/9wj/9wD39yn37zn37zH37yH3'. + '7xD37wj37wDv70Lv50rv50Lv5znv5yHv5xjv5wjv5wDn51Ln5x'. + 'Dn3jHn3iHn3hjn3hDn3gje3oze3nPe3lLe1oze1nPe1lLe1ine'. + '1iHe1hje1hDe1gje1gDW1qXW1mvWzqXWzkLWzhjWzhDWzgjWzg'. + 'DOzrXOzq3OzpzOzgDOxkrOxinOxhjOxhDOxgjOxgDGxqXGxnvG'. + 'xmvGvRjGvRDGvQjGvQDFxbnAvr6/v7+9vaW9vZS9vQi9vQC9tR'. + 'C9tQi9tQC7u7W1tZS1tXu1tTG1tQi1rRC1rQi1rQCtrYytrSGt'. + 'rQitrQCtpYStpSGtpQitpQClpYSlpXulpQClnBClnAilnACcnG'. + 'ucnAicnACclAiclACUlFqUlCmUlAiUlACUjFKUjAiUjACMjFKM'. + 'jEqMjACMhACEhACEewB7ezF7exB7ewB7cwBzcylzcwBzaxBzaw'. + 'BraxhrawhrawBrYxBrYwBjYwBjWgBaWgBaUgCXBwRMAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwkRFBKiJZ4hAAAB7ElEQVR4nI3S+1vS'. + 'UBgHcB67WJmIMWAVdDHEDLBC6Go0slj3Ft0m9RRBWQEmFZFDEM'. + 'Qgt0EMFBY7p/+198hj1kM/9N1+++x73rOd6XT/kStnTx4fPzd9'. + 'uwfOjFhomj7smAhwj/6Cm2O0xUwy6g7cCL99uCW3jtBmE7lsdr'. + 'fvejgpzP7uEDFRRoqy2k8xQPnypo2BUMP6waF9Vpf3ciiSzErL'. + 'XTkPc0zDe3bsHDAcc00yoVgqL3UWN2iENpspff+2vn6D0+NnZ9'. + '6lC5K6RuSqBTZn1O/a3rd7v/MSez+WyIpVFX8GuuCA9SjD4N6B'. + 'oRNTfo5PCAVR0fBXoIuOQzab1XjwwNHx00GOj8/nKtV1DdeArk'. + '24R+0ul9PjmbrHPYl+EipyU0OoQSjg8/m83kl/MMhx0fjCkqio'. + 'SMOE7t4JMAzDsizH81AqSdW2hroLPg4/CEF4PhKNx98vlevrbY'. + 'QQXgV6kXwVfjkTiSXmhYVcSa7DIE1DOENe7GM6lUym0l+EXKks'. + 'K20VAeH2M0JvVgrZfL5Qqkiy0lRVaMBd7H7EZUmsiJJcrTdVja'. + 'wGpdbTLj3/3qwrUOjAfGgg4LnNA5tdQx14Hm00QFBm65hfNzAm'. + '+yIFhFtzuj+z2MI/MQn6Uez5pz4Ua41G7VumB/6RX4zMr1TKBr'. + 'SXAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_silver.png + //========================================================== + $this->imgdata_large[3][0]= 1481 ; + $this->imgdata_large[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAADAF'. + 'BMVEUAAADOzs7Gxsa9vb21tbXOxsbOzsbGzsb3///O1ta1vb2c'. + 'paVSWlpKWlpSY2ve5+97hIze7/9aY2vO5/9zhJRaa3tSY3PGzt'. + 'aMlJxrc3tja3NKUlpCSlK1vcZze4RSWmPW5/+Upb3G3v9zhJxS'. + 'Y3t7jKVaa4TO3veltc6ElK1re5Rjc4ycpbV7hJRaY3M5QlLn7/'. + '/Gzt6lrb2EjJzO3v9ja3vG1ve9zu+1xueltdacrc6UpcaMnL1C'. + 'SlqElLV7jK1zhKVre5zW3u/O1ue1vc6ttcaMlKVze4xrc4RSWm'. + 'tKUmPG1v+9zve1xu+tveeltd6crdbe5/+9xt6cpb17hJxaY3s5'. + 'QlrW3vfO1u/Gzue1vdattc6lrcaUnLWMlK2EjKVze5Rrc4xja4'. + 'RSWnNKUmtCSmO9xuecpcZ7hKVaY4TW3v/O1vfGzu+1vd6ttdal'. + 'rc69xu+UnL2MlLWEjK1ze5xrc5R7hK1ja4zO1v+1veettd6lrd'. + 'aMlL3Gzv/39//W1t7Gxs61tb29vcatrbWlpa2cnKWUlJyEhIx7'. + 'e4TW1ufGxta1tcZSUlqcnK3W1u+UlKW9vda1tc57e4ytrcalpb'. + '1ra3vOzu9jY3OUlK29vd6MjKWEhJxaWmtSUmNzc4xKSlpjY3tK'. + 'SmNCQlqUjJzOxs7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAD///9fnkWVAAAAAnRSTlP/AOW3'. + 'MEoAAAABYktHRP+lB/LFAAAACXBIWXMAAABFAAAARQBP+QatAA'. + 'AB/klEQVR42mNgxAsYqCdd3+lcb4hLmj8wMMvEu8DCMqYbU9op'. + 'UEFB2MTb26eyysomFl06XEEhUCHLpAKo2z/fujikEUVaXUFBMB'. + 'BouLePuV+VVWGRciIXknSEsImCQd3//xwmPr65llaFcSFJHkjS'. + '3iYmWUDZ//8NfCr989NjNUMSUyTg0jneSiaCINn/gmlVQM12qg'. + 'lJnp5waTMTE5NAkCyHWZW/lXWNfUlikmdYK0zax7siS4EDKJtd'. + 'mQeU1XRwLBdLkRGASucWmGVnZ4dnhZvn5lmm29iVOWpnJqcuko'. + 'JKR1Wm5eTkRKYF5eblp9sU2ZeUJiV7zbfVg0pH56UFBQXNjIqK'. + 'jgkujItX1koKTVmYajsdKu2qETVhwgSXiUDZ2Bn9xqUeoZ5e0t'. + 'LzYYZ3B092ndjtOnmKTmycW1s7SHa+l5dtB8zlccE6RlN0dGbM'. + 'mDVbd5KupNBcL6+F82XgHouLj5vRP2PWLGNdd4+ppnxe8tJec6'. + 'XnNsKkm0uVQ5RDRHQTPTym68nPlZbvkfYCexsa5rpJ2qXa5Umm'. + 'ocmec3m8vHjmSs+fgxyhC5JDQ8WSPT2lvbzm8vDIe0nbtiBLN8'. + '8BigNdu1B6Lsje+fPbUFMLi5TMfGmvHi/puUAv23q2YCTFNqH5'. + 'MvPnSwPh3HasCbm3XUpv+nS5VtrkEkwAANSTpGHdye9PAAAASn'. + 'RFWHRzaWduYXR1cmUANGJkODkyYmE4MWZhNTk4MTIyNDJjNjUx'. + 'NzZhY2UxMDAzOGFhZjdhZWIyNzliNTM2ZGFmZDlkM2RiNDU3Zm'. + 'NlNT9CliMAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bl_purple.png + //========================================================== + $this->imgdata_large[4][0]= 1149 ; + $this->imgdata_large[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACAV'. + 'BMVEX/////////7///5///1v//xv//rf//pf//lP//jP//hP//'. + 'c///a///Wv//Wvf/Uv//Sv//Qv//Qvf/Off/Mf//Kf//If//If'. + 'f/GP//GPf/EP//EPf/CP//CPf/CO//AP//APf3Oe/3Kff3Ke/3'. + 'Ie/3GO/3EO/3AO/vSu/vSufvOefvMefvIefvGOfvEOfvCOfvAO'. + 'fnUufnSufnMd7nId7nGN7nGNbnEN7nCN7nAN7ejN7ejNbec97e'. + 'c9beUtbeQtbeIdbeGNbeENbeCNbeANbWpdbWa9bWQs7WGM7WEM'. + '7WCM7WAM7Otc7Orc7OnM7OSsbOIb3OGMbOEMbOCMbOAM7OAMbG'. + 'pcbGnMbGe8bGa8bGKbXGEL3GCL3GAL3FucXBu73AvsC/v7+9pb'. + '29Ka29GLW9ELW9CLW9AL29ALW5rrm1lLW1e7W1MbW1GKW1EK21'. + 'CLW1CK21AK2tjK2thKWtMaWtIaWtGJytCK2tCKWtAK2tAKWlhK'. + 'Wle6WlEJylCJylAKWlAJyca5ycGJScEJScCJScAJycAJSUWpSU'. + 'UoyUKZSUEIyUCIyUAJSUAIyMUoyMSoyMIYSMEISMCISMAIyMAI'. + 'SECHuEAISEAHt7MXt7EHt7CHt7AHt7AHNzKXNzEGtzAHNzAGtr'. + 'GGtrEGNrCGtrAGtrAGNjCFpjAGNjAFpaAFpaAFIpZn4bAAAAAX'. + 'RSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsS'. + 'AdLdfvwAAAAHdElNRQfTAwkRFB0ymoOwAAAB9UlEQVR4nGNgIA'. + 'K42hhqGtm5+WFIWClKycvLK6gbuARGoEj4aMjLSElISUir6Tt7'. + 'x+aEIWR8leQlwEBSTc/CK7awLguuR0lGQkJMVFRUTFJVzwko1d'. + 'oFk9OQl5IQE+Dh5hVR0TV3CkkvbJgyASJjDZIR5GBl5eRX0TH1'. + 'DEqrbJ2ypBEspSgvJSXKw8bMxMavbOLoGZNf1TZlybw4oIyfLN'. + 'BxotxsLEzsQiaOHkFpBQ2905esrAZK2SpIAaUEuDm5+LTNPAKj'. + 'C+pbps1evrIDKGWnLictKSkuLKyoZQyUya9o7Z2+YMXKGUApew'. + 'M9PTVdXR0TEwf3wOjUirruafOXL18xFyjl72Kpb25qaurg4REU'. + 'EFVe2zJ5zpLlK1aCpbydnZ2dnDwDA6NTopLLeiZNXbB8BcTAyP'. + 'TQ0JDg4KCY1NS83JKmiVOBepYvX9UPlAovzEiPSU/LLyior2vq'. + 'mjZr3vLlIF01IC+XVhUWFlZW1Lc290ycOGfxohVATSsXx4Oksn'. + 'vaWlsb2tq6J0+bM2/RohVA81asbIcEYueU3t7JU6ZNnwNyGkhm'. + '+cp5CRCppJnzZ8+ZM3/JUogECBbBIixr8Yqly8FCy8F6ltUgoj'. + 'lz7sqVK2ByK+cVMSCDxoUrwWDVysXt8WhJKqG4Y8bcuTP6qrGk'. + 'QwwAABiMu7T4HMi4AAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_gray.png + //========================================================== + $this->imgdata_large[5][0]= 905 ; + $this->imgdata_large[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAABO1'. + 'BMVEX////////3///39/fv7+/e5+fW3t7Wzs7WxsbG1tbGzsbG'. + 'xsbDxMS/v7++wMC+v7+9zsa9xsa9vb29tbW9ra29pa24uLi1xs'. + 'a1vb21tbWxtrattbWmpqalra2cra2cpaWcnJycjIyUpaWUnJyU'. + 'lJSUjIyMnJyMnJSMlJSMlIyMjJSMjIyElJSElIyEjIyEhIR7jI'. + 'x7hIR7hHt7e3t7e3N7e2tzhIRze3tze3Nzc3Nre3trc3Nrc2tr'. + 'a2tjc3Njc2tja3Nja2tjY2NjWlpaa2taY2taY2NaY1paWlpaUl'. + 'JSY2NSY1pSWlpSWlJSUlJSUkpKWlpKWlJKUlpKUlJKUkpKSkpK'. + 'SkJCUlJCUkJCSkpCSkJCQkI5Sko5QkI5Qjk5OUI5OTkxQkIxOT'. + 'kxMTkxMTEpMTEhMTEhKSkYISEpy7AFAAAAAXRSTlMAQObYZgAA'. + 'AAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdE'. + 'lNRQfTAwkRFQfW40uLAAABx0lEQVR4nI3SbXfSMBQA4NV3nce5'. + 'TecAHUywRMHSgFuBCFsQUqwBS1OsWQh0GTj//y8wZUzdwQ/efM'. + 'tzcm/uuXdj4z9ic/PR9k4qk1qDnf0X2/uZzKt8GaRvSubg4LVp'. + 'mkWzCGAT/i3Zsm2XNQHLsm2n2937LaaNnGoJFAEo27B50qN0ay'. + 'Wg26lXsw8fP8nmzcJb2CbsnF5JmmCE8ncN404KvLfsYwd7/MdV'. + 'Pdgl/VbKMIzbuwVgVZw2JlSKJTVJ3609vWUY957lgAUd1KNcqr'. + 'yWnOcOPn8q7d5/8PywAqsOOiVDrn42NFk+HQ7dVuXNYeFdBTpN'. + 'nY5JdZl8xI5Y+HXYaTVqEDp1hAnRohZM03EUjMdhn5wghOoNnD'. + 'wSK7KiiDPqEtz+iD4ctdyAifNYzUnScBSxwPd6GLfRURW7Ay5i'. + 'pS5bmrY8348C5vvUI+TLiIVSJrVA0heK/GDkJxYMRoyfCSmk4s'. + 'uWc3yic/oBo4yF374LGQs5Xw0GyQljI8bYmEsxVUoKxa6HMpAT'. + 'vgyhU2mR8uU1pXmsa8ezqb6U4mwWF/5MeY8uLtQ0nmmQ8UWYvb'. + 'EcJaYWar7QhztrO5Wr4Q4hDbAG/4hfTAF2iCiWrCEAAAAASUVO'. + 'RK5CYII=' ; + + //========================================================== + // File: bl_brown.png + //========================================================== + $this->imgdata_large[6][0]= 1053 ; + $this->imgdata_large[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABoV'. + 'BMVEX////Gzs7GvbXGrZTGpXu9nHO1nHO1nIy9taXGxs7GtaXO'. + 'nHPGlFrGjEq9hEq1hEqte0Klczmcazmce1KtnIzGxsbGvb3OlF'. + 'LOlFq9hFKte0qcc0KUYzGEWimMc1K9ta3OnGvOnGPWnGO9jFq9'. + 'jFKlc0KUazmMYzl7UilzUjGtpZzGxr3GnGPWpWvepXO1hFJ7Wj'. + 'FrSiFjUjG1ra3GnHPvxpT/5733zpythFKUa0KEYzlzUilaOSF7'. + 'Wjm9jErvvYz/99b///f/78bnrYS1hFqle0p7UjFrSiljQiFCMR'. + 'iMhHO9lGvGjFLWnGv/3q3////erXuthEqlc0paQiFKMRhSQin/'. + '1qX/997//++cc0pjSilaQilKORhCKRiclIy9pYzGlGPntYT33q'. + '3vvZSEWjlSOSE5KRB7c2O1lHutczmthFqte1JrWkqtjGtCKRBa'. + 'SjmljGuca0KMYzGMaznOztaclISUYzmEWjFKOSF7a1qEYzFaSi'. + 'GUjISEa0pKOSm9vb2llIxaQhg5IQiEc2tzY0paORilnJy1raVS'. + 'OSljUkJjWkKTpvQWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkREiei'. + 'zP2EAAAB9UlEQVR4nGWS/VfSUBjHL5QluhhBxtwyWcCus5Blpm'. + 'wDC4ONaWXCyBi7RMZmpQ2Bypm9W/byV3cHHo/W88s95/s5z/d5'. + 'uwCcCh/4L3zAf+bs0NC588On9QAYGSUuBINk6GI4cmnsBLk8Go'. + '1SFEGMkzRzZeLq5JE8FvDHouw1lqXiCZJOcnCKnx4AcP0GBqmZ'. + 'mRgRT9MMB4Wbs7cGSXNRik3dnp9fiMUzNCNKgpzN9bsaWaQo9s'. + '7dfH7pXiFTZCBU1JK27LmtBO8TDx7mV1eXHqXXyiIUFLWiVzHx'. + 'BxcJIvV4/cn6wkqmWOOwmVE3UQOAp6HxRKL5bGPj+VwhUhalFq'. + '8alm5vAt+LlySZTsebzcKrraIIW4JqZC3N3ga+1+EQTZKZta1M'. + 'pCZCSeDViqVrThsEdsLJZLJYLpZrHVGScrKBvTQNtQHY6XIM02'. + 'E6Ik7odRW1Dzy3N28n3kGuB3tQagm7UMBFXI/sATAs7L5vdbEs'. + '8Lycm923NB0j5wMe6KOsKIIyxcuqauxbrmlqyEWfPmPy5assY1'. + 'U1SvWKZWom9nK/HfQ3+v2HYZSMStayTNN0PYKqg11P1nWsWq7u'. + '4gJeY8g9PLrddNXRdW8Iryv86I3ja/9s26gvukhDdvUQnIjlKr'. + 'IdZCNH+3Xw779qbG63f//ZOzb6C4+ofdbzERrSAAAAAElFTkSu'. + 'QmCC' ; + + //========================================================== + // File: bl_darkgreen.png + //========================================================== + $this->imgdata_large[7][0]= 1113 ; + $this->imgdata_large[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. + 'BMVEX////////3///v///n/+/e99bW/+/W99bO786/v7++vr69'. + '/96999a7wb24vbu1/9a1zqW1u7itxrWosq6l772l1qWlxrWlxq'. + '2lva2cxpSU562U3q2UxqWUvaWUpZyM77WM57WMvYyMtZyMrZyM'. + 'pZSMnJSEvZyEtYyErZSElIx7zpR7xpx7xpR7vZR7jIRz1pRzxp'. + 'RzjIRrzpRrzoxrxoxrtYRrrYxrrXtrpYRrhHNjzoxjxoxjxoRj'. + 'vYRjtYRjrXtjpXtjlGNje2tazoxazoRaxoxaxoRavYRatYRatX'. + 'tarXtapXNanHNajFpae2tSzoRSxoRSvXtStXtSrXtSrXNSpXNS'. + 'nHNSnGtSlGtSlGNSjGtSjGNKvXtKtXNKrXNKpWtKnGtKlGNKjG'. + 'NKhGNKhFJKc1pKa1JCrWtCpWtCnGtClGNCjGNCjFpChFpCe1JC'. + 'a1JCY1I5pWs5nGM5lGM5jFo5hFo5e1o5c0o5WkoxjFoxhFoxhF'. + 'Ixe1Ixc1Ixc0oxa0ophFIpe0opc0opa0opa0IpY0IpWkIpWjkp'. + 'UkIpUjkhc0oha0IhY0IhWjkhWjEhUjkhUjEhSjEhSikhQjEhQi'. + 'kYWjkYSjEYSikYQjEYQikQSikQQikQQiEQOSExf8saAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwkRFCaDkWqUAAAB+ElEQVR4nI3S+1vS'. + 'UBgHcGZlPV0ks/vFrmQWFimJjiwiYUJWjFBWFhClyZCy5hLrwA'. + 'x2EIwJC1w7zf2vnU0re+iHvs9++7x7zznvORbLf+TA6ct9fYMX'. + 'jrfAUYefpp+/iM1ykxf/lmuhUZ/PTwXC8dml5Wcd23o5H5Mk6b'. + '5NUU8icXbhS67rNzn9JDnguOEYGQtEEtwC+Crs3RJ76P5A/znr'. + 'vsNX7wQnEiwHCtK7TTkW8rvdZ9uJtvZTLkxpHhSrP66bNEj7/P'. + '3WNoLYeeSWQQCIpe9lQw7RNEU5rDsIYtcJ14Nocg7kRUlBNkxn'. + 'YmGKcp7cv3vPwR7XOJPmc0VYU3Sv0e9NOBAYG7Hbz/cMjTMveZ'. + 'CHkqxuTBv0PhYJB4N3XR6PJ5rMAPMnpGUxDX1IxSeMTEaZp1OZ'. + 'nGAIQiYtsalUIhFlmGTy3sO3AizJCKn6DKYryxzHsWyaneMzr6'. + 'cWxRVZVlFTe4SpE3zm+U/4+whyiwJcWVMQNr3XONirVWAklxcE'. + 'EdbqchPhjhVzGpeqhUKhWBQhLElr9fo3pDaQPrw5xOl1CGG1JE'. + 'k1uYEBIVkrb02+o6RItfq6rBhbw/tuINT96766KhuqYpY3UFPF'. + 'BbY/19yZ1XF1U0UNBa9T7rZsz80K0jWk6bpWGW55UzbvTHZ+3t'. + 'vbAv/IT+K1uCmhIrKJAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bl_green.png + //========================================================== + $this->imgdata_large[8][0]= 1484 ; + $this->imgdata_large[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMMFjM4kcoDJQAABVlJREFUeNq9ll2MJFUVx3/11V'. + 'Vd/TE9vU0v4zLDwJIF16jBqLAPhsRXEiDqg0QTJiQSjcSNvCzw'. + 'sBEDDxizhvAAxBgf1oR9QF9NiE9ESFZkQyZB5WtddmdnZ3qqqr'. + 'uqbt367Cofqu3ZZpWVaDzJfbkf53//55z/PVdZXV3l/2H6f7Lp'. + '5VdOV/4Nb+GmHpUeA7AdBNxc3kafNb73jRPK9Xwon8ToxVefqU'. + 'b91wibH5EkCQBCizFihTSviHUHR0hWws9xe3wvJ7/7nPKpgX5y'. + '9oFqt3eOgWniRBoAbUBGGqZUibSYaeoT2B5bnkdaSA6793Cv/S'. + 'QPPbihXBfo5VdOV+8dfgnvwAU62YH5fCZ12sDujFkwyegCqTrB'. + 'iUOKTOJKj8jr88jS8zy6cXwBTP048nuHX0I0nDlIp7RpTG7kM0'. + 'sdyAYsTVukUuWGhlWHMq0ITL92lnUp9R1Obz/GmTNnqn9bDD8/'. + '+0D1oX0O0zQZZDYCsK2j3Gl9jQqDfHiei8GfiKVLlsZkJaBAN1'. + '0i6PgwUbB0GxG5/PrtE/xLRr959Znqw9452oVNI+jiJhnr1pe4'. + 'k29zB1/nFr5Kj7tpt1YYhJ0FJ7nUYbcJQBgahN2MzeCP/OipR6'. + 'prgN6Qr6ELFQFUWoRpNVjlKwxZB8DCpE+PtfEKqV1cUzxpVudu'. + 'GTBHA5Y1g99e+dUio9O/P1Vpq+/WE5GGjDSMoAtAQjrf3C52IP'. + 'QxpY4WK2hpReka9Gfrhqgz0bACRoCWjDh56kQ1z9FeuUUQxVhK'. + 'B92sD1VahM+bAJgcoJhGjP/6Ln8rAgDiRCVRKiIzxMkkodBJ85'. + 'im1IlEHbE4k1xyNveL4YP8HarmGJIOpqyjeQmfNHmTvnqZTWBt'. + 'vIJXpPwlukJSuSTKGK3pEwtJmiX00ZlInTyNscImO6XBITvH1c'. + '8vVt2OucdKvIyeKRTNCivsEMgcpg6taYs30nfq0Gqg6hOSSFJ4'. + 'BSnJPht0IqEjWmOGocEI6F0J94F0qaL6BntTF0MtUfweKQKAPU'. + 'Wwp4OcVnQAmVb0p9DLOzjEhEKnGRmoRc7EzRGlwA6NujAKG4yP'. + '6Sjwc4aVznZ7DK0xXdkDoJf0kGmFBniFBOBGcZSCCSKd0IwN0k'. + 'IS+QZWCGVZex4BnUxya3+Zt9iugQbcRFpIAtuHvAZulPUdLhUJ'. + 'RqegI3WcqaSXddlT3idsWMSRRGkEtNwmyTifAwyBo7LP+11J0e'. + '7tM7pZOYblHkBLcqZ5LcYtw6Wbd4CM3SpE9foYZsIHoqDKCrbz'. + 'mLSQtPwmuhXgtBLs0GBdbXOhFGB7WBKO2F8GXt9/VO97Ya3atF'. + '7nUHnwGjGGQqcPxFEdFqURkEidiZszAERoYIsGju1hq21kWee3'. + 'bw15+8WpsvAy3K1+i3JkkhZyPpxxjjPOsfOYiZ+TFhLPzQnHOU'. + 'tpzGB2dgA4tscIkKIx19Cxg/fPL7vQJu47eXt1VvsDK8pwPueZ'. + 'PuZoQMOqhRoJHSs0kKLBWjvjYinmeQGw1TaX1RFdfZ3LMzYLjA'. + 'C++dkn6AaH2Nobk6cxEzdnuG0TdC8zvdJkN0hqkFkO/jwL0fxa'. + 'so8sBcuFzQ+/+MRC+BeAHnpwQzn++ee5KT9Eshuy46dcKAXm32'. + '0uzPQhS4GttkH2GQID2Wc0Y4LtAbDxhZ/x5A+e/uTG9+jGceXH'. + '9/ySnnIXnUzOxXe1038mW3ZynNmam4yYWkO+f9cv+Oljz16/lV'. + '9tDz/9nerc1hm8ZEScSRK7VvtYl1i1dklsOKyvc+zg/bzw1O8+'. + '/efkajt56kR1ydlEJBc5H46xzbrJ3dY9wrB7hGcff+6/+279L+'. + '0fHxyiE8XMLl4AAAAASUVORK5CYII=' ; + + //========================================================== + // File: bl_blue.png + //========================================================== + $this->imgdata_large[9][0]= 1169 ; + $this->imgdata_large[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACEF'. + 'BMVEX/////////7//35//v1v/exv/Wvf/Wrf/Wpf/Orf+/v7+9'. + 'tc69jP+9hP+5ucW1tc6tlP+rq7Wlpdalpcalpb2cnM6cnMacc/'. + '+cWv+UlLWUjN6UjK2Uc/+Ma/+MUv+EhKWEa/+EQvd7e8Z7e7V7'. + 'e6V7c957Wv9za9Zza8ZzSv9ra5xrSv9rOf9rMe9jUudjQv9jOe'. + '9aWpRaUt5aUpRaSu9aSudSUoxSSs5SSoxSMf9KQtZKOfdKMedK'. + 'Kf9KKe9CKf9CKb1CKa1CIfdCIedCId45MXs5Kfc5If85Iec5Id'. + 'Y5GP8xMbUxMXsxKc4xKZQxIf8xGP8xGO8xGN4xGNYxGL0xGK0p'. + 'KXMpIYwpGP8pGO8pGOcpGNYpGM4pEP8pEPcpEOcpEN4pENYpEM'. + 'YpEL0hGKUhEP8hEPchEO8hEOchEN4hENYhEM4hEMYhELUhCP8h'. + 'CO8hCN4YGJwYGGsYEL0YEK0YEHMYCN4YCM4YCMYYCL0YCKUYAP'. + '8QEJQQEIwQEHsQEGsQCM4QCLUQCK0QCKUQCJwQCJQQCIwQCHMQ'. + 'CGsQAP8QAPcQAO8QAOcQAN4QANYQAM4QAMYQAL0QALUQAKUQAJ'. + 'QQAIQICGsICGMIAO8IANYIAL0IALUIAK0IAKUIAJwIAJQIAIwI'. + 'AIQIAHsIAHMIAGsIAGMAAN4AAMYAAK0AAJQAAIwAAIQAAHMAAG'. + 'sAAGMAAFrR1dDlAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFRPMOZ'. + '/2AAAB+klEQVR4nGNgIAIIqeqZmBqpi2JISNml5lVXV3d198Yo'. + 'oUjwm1SnxsbGRsSm5ZfNXO4tjCTjVh0ABhFx6QV9E1Y0S8JkuN'. + '3yAgLc7W3t/QPi4jPKJ8ye1yoIlTKpjvVy15eVUbN0i4zKLJ8w'. + 'ae6qcKgLqmMj3PUFWFl5NJ0CExLLJzbNW7BWCyxlXR0ba6/Axs'. + 'zELmfnkRBT0QiSKgXJCOflxUbYy3KyMHEoOrtEZ1c2TZ6/cMl6'. + 'eaCUamdsbIC7tjgPr4SBS3BMMVDTwkXr1hsDpYy6UmMj/O0tdX'. + 'QNbDxjknJLWqYsXLx0vStQynxGflpkZGCgs7Onp29SbtNkoMy6'. + 'pevCgFJWy3oyMuKjgoKCPWNCvEuqWhcsWrJ06XqQlPnMvrKyrM'. + 'TomJjkZAfHlNa2qdOWrlu63gcopbG8v7+hvLwip7g4JdSxsLZu'. + '8dKlS9ettwBKic2eNXHChIkTG5tKqgpr2uo6loLAehWQx0LnzJ'. + '49p6mpeXLLlNq6RUvqly6dvnR9Bx9ISnnlvLmT582bMr9t4aL2'. + '+vrp60GaDCGB6Ld6wfwFCxYCJZYsXQ+SmL6+FBryInVrFi1atH'. + 'jJkqVQsH6pNCzCJNvXrQW6CmQJREYFEc2CYevXrwMLAyXXl0oz'. + 'IAOt0vVQUGSIkabkDV3DwlzNVDAksAAAfUbNQRCwr88AAAAASU'. + 'VORK5CYII=' ; + + //========================================================== + // File: bs_red.png + //========================================================== + $this->imgdata_small[0][0]= 437 ; + $this->imgdata_small[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. + 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. + 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. + 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. + 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. + 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGDNEMgOYAAAAm0'. + 'lEQVR4nI3Q3RKCIBAFYGZMy9RKzX7MVUAUlQTe/+kS0K49d3wD'. + '7JlFaG+CvIR3FvzPXgpLatxevVVS+Jzv0BDGk/UJwOkQ1ph2g/'. + 'Ct5ACX4wNT1o/zzUoJUFUGBiGfVnDTYGJgmrWy8iKEtp0Bpd2d'. + 'jLGu56MB7f4JOOfDJAwoNwslk/jOUi+Jts6RVNrC1hkhPy50Ef'. + 'u79/ADQMQSGQ8bBywAAAAASUVORK5CYII=' ; + + + //========================================================== + // File: bs_lightblue.png + //========================================================== + $this->imgdata_small[1][0]= 657 ; + $this->imgdata_small[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABVl'. + 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. + 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. + '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. + 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. + 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. + 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. + 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. + 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. + 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. + 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGTok'. + '9Yp9AAAAtElEQVR4nGNgIBaw8wkpKghzwvksPAKiUsraprYiLF'. + 'ARXkE2JiZ1PXMHXzGIAIekOFBE08TGLTCOCyzCLyvDxsZqZOnk'. + 'E56kAhaRV9NQUjW2tPcMjs9wBYsY6Oobmlk7egRGpxZmgkW0zC'. + '2s7Jy9giKT8gohaiQcnVzc/UNjkrMLCyHmcHr7BYREJKTlFxbm'. + 'QOxiEIuKTUzJKgQCaZibpdOzQfwCOZibGRi4dcJyw3S4iQ4HAL'. + 'qvIlIAMH7YAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_gray.png + //========================================================== + $this->imgdata_small[2][0]= 550 ; + $this->imgdata_small[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1'. + 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. + 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. + 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. + 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. + 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. + 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. + '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. + 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. + 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA'. + 'AAsSAdLdfvwAAAAHdElNRQfTAwkUGiIctEHoAAAAfElEQVR4nI'. + '2N2xKDIAwF+bZ2kAa8cNFosBD//yvKWGh9dN+yk9kjxH28R7ze'. + 'wzBOYSX6CaNB927Z9qZ66KTSNmBM7UU9Hx2c5qjmJaWCaV5j4t'. + 'o1ANr40sn5a+x4biElrqHgrXMeac/c1nEpFHG0LSFoo/jO/BeF'. + 'lJnFbT58ayUf0BpA8wAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bs_greenblue.png + //========================================================== + $this->imgdata_small[3][0]= 503 ; + $this->imgdata_small[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAxl'. + 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. + '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. + '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. + 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. + 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. + 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. + 'dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfT'. + 'AwkUGTIqLgJPAAAAqklEQVR4nI2QVxOCMBCEM6Mi2OiCvSslJB'. + 'CUoqjn//9TYgCfubf9Zu9uZxFqO+rscO7b6l/LljMZX29J2pNr'. + 'YjmX4ZaIEs2NeiWO19NNacl8rHAyD4LR6jjw6PMRdTjZE0JOiU'. + 'dDv2ALTlzRvSdCCfAHGCc7yRPSrAQRQOWxKc3C/IUjBlDdUcM8'. + '97vFGwBY9QsZGBc/A4DWZNbeXIPWZEZI0c2lqSute/gCO9MXGY'. + '4/IOkAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bs_yellow.png + //========================================================== + $this->imgdata_small[4][0]= 507 ; + $this->imgdata_small[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAzF'. + 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. + 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. + 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. + 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. + 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. + '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. + 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAH'. + 'dElNRQfTAwkUGSDZl3MHAAAAqElEQVR4nI3QWRNDMBAA4My09E'. + 'IF1SME0VT1okXvM/3//6kEfbZv+81eswA0DfHxRpOV+M+zkDGG'. + 'rL63zCoJ2ef2RLZDIqNqYexyvFrY9ePkxGWdpvfzC7tEGtIRly'. + 'nqzboFKMlizAXbNnZyiFUKAy4bZ+B6W0lRaQDLmg4h/k7eFwDL'. + 'OWIky8qhXUBQ7gKGmsxpC+ah1TdriwByqG8GQNDNr6kLjf/wAx'. + 'KgEq+FpPbfAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_darkgray.png + //========================================================== + $this->imgdata_small[5][0]= 611 ; + $this->imgdata_small[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABJl'. + 'BMVEX////////o8v/f6O7W4OnR3PXL1OTL0evEyLvCzePAwMC/'. + 'v7a8wsq7t7C1xum1vtS1q6GzopmyxeKsrsOqvNWoq7anvN+nsb'. + 'qhrcGgqbGfpq6cp7+bqMuVmJKRm7yPlKKMnL6FkKWFipOEkLSE'. + 'j6qEhoqAiaB+jqd8haF7hZR4iJt4g5l3hZl2gIt2cod1hJVzeY'. + 'VzboJvhp9sfJJsb41peY1pd5xpdoVod4xndI5lcHxka4BjcYVg'. + 'Z3BfboFbb4lbZnZbYntaZ4laZYVZV3JYYWpXX3JWWm5VX4RVW2'. + 'NUYX9SXHxPWn5OVFxNWWtNVXVMVWFKV3xHUGZGU3dGTldFSlxE'. + 'Sk9ESXBCRlNBS3k/SGs/RU4+R1k9R2U6RFU2PUg0PEQxNU0ECL'. + 'QWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAA'. + 'CxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGQmbJetrAAAAtklEQV'. + 'R4nGNgwAK4JZTNNOWlYDxhMT4ZDTOzQE1uMF9CiJWVU0LbxDlS'. + 'G8QVF+FnZ2KRNHAIiPUHaZGSlmZj5lH19A1KjLUA8lXU5MWllF'. + 'yjo30TYr2BfG19G11b37CEeN84H38gX1HbwTUkOjo+zjfG3hLI'. + 'l1exCvCNCwnxjfMz0gTyRdXNHXx9fUNCQu2MwU6SN3ZwD42LCH'. + 'W30IK4T8vUJSAkNMhDiwPqYiktXWN9JZj7UQAAjWEfhlG+kScA'. + 'AAAASUVORK5CYII=' ; + + + //========================================================== + // File: bs_darkgreen.png + //========================================================== + $this->imgdata_small[6][0]= 666 ; + $this->imgdata_small[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABX1'. + 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. + 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. + 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. + 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. + '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. + 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. + 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. + 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. + 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. + 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAwkUGRjxlcuZAAAAtElEQVR4nGNgIBZw8osqqIpzw/msfI'. + 'IiUmr6lo6SbFARASEOJiYtQ2uXADmIAJeEGFBE18LBMySBBywi'. + 'LC/LwcFiZuvmH5WiAxZR0tRW1DC3dfYJS8zyAouYGBibWtm7+o'. + 'TEpZfkgEX0rG3snNx9Q2NSCksgaqRd3Ty8gyLiU/NKSiDmcPsF'. + 'BodHJ2UUlZTkQ+xikIlNSE7LLgECZagL2VQyc0H8YnV2uD94jS'. + 'ILIo14iQ4HALarJBNwbJVNAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_purple.png + //========================================================== + $this->imgdata_small[7][0]= 447 ; + $this->imgdata_small[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAnF'. + 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. + 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. + 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. + 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. + 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGS'. + 'o5QpoZAAAAnElEQVR4nI3Q2xJDMBAG4MyQokWrZz3oSkJISJH3'. + 'f7dK0Gv/Xb7J7vyzCK0NjtPsHuH/2wlhTE7LnTNLCO/TFQjjIp'. + 'hHAA6bY06LSqppMAY47x+04HXTba2kAFlmQKr+YuVDCGUG2k6/'. + 'rNwYK8rKwKCnPxHnVS0aA3rag4UQslUGhrlk0Kpv1+sx3tLZ6w'. + 'dtYemMkOsnz8R3V9/hB87DEu2Wos5+AAAAAElFTkSuQmCC' ; + + + //========================================================== + // File: bs_brown.png + //========================================================== + $this->imgdata_small[8][0]= 677 ; + $this->imgdata_small[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABaF'. + 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. + 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. + 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. + 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. + '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. + 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. + 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. + 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. + 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. + 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. + 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLd'. + 'fvwAAAAHdElNRQfTAwkUGho0tvl2AAAAtklEQVR4nGNgIBaoSg'. + 'mLKGpowfkGMty8AqJKpi4mRlAROR5ONg4JFUv3YHOIgDo/HwsT'. + 'q6yps29EsjZYREFIkJ2ZS9/OMzA20wEsIi8uKSZtaOPmH5WSFw'. + 'YW0VRW07Vw8vCLSMguLwCL6FlaObp6B0TGZxSXQ9TouHv6+IXG'. + 'JGYWlpdDzNEKCgmPjkvLKS0vL4LYxWAen5SelV8OBNZQFxrZ5h'. + 'aC+GX2MDczMBh7pZakehkTHQ4AA0Am/jsB5gkAAAAASUVORK5C'. + 'YII=' ; + + //========================================================== + // File: bs_blue.png + //========================================================== + $this->imgdata_small[9][0]= 436 ; + $this->imgdata_small[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. + 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. + 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. + 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. + 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. + 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGhNNakHSAAAAmk'. + 'lEQVR4nI3P2xKCIBAGYGfM6SBWo1nauIqogaDA+z9dK9Lhrv47'. + 'vtl/2A2CfxNlJRRp9IETYGraJeEb7ocLNKznia8A7Db7umWDUG'. + 'sxAzhurxRHxok4KQGqCuEhlL45oU1D2w5BztY4KRhj/bCAsetM'. + '2uObjwvY8/oX50JItYDxSyZSTrO2mNhvGMbaWAevnbFIcpuTr7'. + 't+5AkyfBIKSJHdSQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bs_green.png + //========================================================== + $this->imgdata_small[10][0]= 452 ; + $this->imgdata_small[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAn1'. + 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. + '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. + 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. + '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. + 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. + 'AIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAw'. + 'kUGgW5vvSDAAAAnklEQVR4nI3QSxKCMAwA0M4gqCgoiiJ+kEAL'. + 'LQUq0PufzX7ENdnlJZNkgtDS2CYZvK6bf+7EoKLA9cH5SQzv6A'. + 'YloTywsAbYr44FrlgrXCMJwHl3xxVtuuFkJAPIcw2tGB9GcFli'. + 'oqEf5GTkSUhVMw2TtD0XSlnDOw3SznE5520vNEi7CwW9+Ayjyq'. + 'U/3+yPuq5gvhkhL0xlGnqL//AFf14UIh4mkEkAAAAASUVORK5C'. + 'YII=' ; + + + //========================================================== + // File: bs_white.png + //========================================================== + $this->imgdata_small[11][0]= 480 ; + $this->imgdata_small[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFTsY/ewvBQAAAW1JREFUeJytkz2u4jAUhT/jic'. + 'gfBUKiZhE0bIKeVbCWrIKenp6eDiGlCEEEBArIxvzGU4xeZjLk'. + 'jWb05lRXuvbx+exr4bouX1Xjyw7Atz81F4uFBYjjGIDhcCjq1o'. + 'k6nN1uZwFerxfP55Msy1itVmRZBsB4PK6YveHkeW5d18XzPIIg'. + 'wPd9Wq0WnU6HMAxJkoQoiuynOIfDwUopkVIihKAoCgAcx6Hdbm'. + 'OMIU1T5vN55eBKEikljUYDIX6kFUKU9e8aDAZlmjcca+1b7TgO'. + '1+uVy+VS9nzfr8e53++VzdZaiqIgz3OMMWitOZ/PaK0JgqDeRC'. + 'mF53lIKYGfr3O73TDGoJQiTVO01nS73XqT4/FIs9kkCAIej0eZ'. + 'brPZEMcxSZKgtQZgMpmIWpN+vy+m06n1PK9yTx8Gy+WS/X5Pr9'. + 'er9GuHLYoiG4YhSilOpxPr9Zrtdlti/JriU5MPjUYjq7UuEWaz'. + '2d+P/b/qv/zi75oetJcv7QQXAAAAAElFTkSuQmCC' ; + + + //========================================================== + // File: bs_cyan.png + //========================================================== + $this->imgdata_small[12][0]= 633 ; + $this->imgdata_small[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABPl'. + 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. + '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. + 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. + '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. + 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. + '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. + '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. + 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. + 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwkUGQDi+VPPAAAAtElEQVR4nGNgIBawikipyIiy'. + 'wfksfJpGRkamNtr8LFARPiMFHmFDcztXfwGoFi0jLiZuZRtnry'. + 'BddrCIiJEGL6eklYO7X3iCOFhE2thESdHawdUnJDZFDiyiamZh'. + 'aevk5h0UlZSpBhaRtbN3dPHwDY5MSM+EqBFzc/f0DgiLTkjLzI'. + 'SYw6bjHxgaEZeckZmpD7GLQSAqJj4xNRMIBGFuFtRLA/ENhGBu'. + 'ZmDgkJBXl5fgIDocAAKcINaFePT4AAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bs_bluegreen.png + //========================================================== + $this->imgdata_small[13][0]= 493 ; + $this->imgdata_small[13][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAvV'. + 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. + 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. + '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. + 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. + '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. + 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. + 'AJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGxNUcXCT'. + 'AAAAqUlEQVR4nI2Q1xKCMBREM2NHLCCogAGCjd6SqLT8/2cZKT'. + '6zb3tm987OBWCsXoejp8rC35fi4+l6gXFZlD0Rz6fZ1tdDmKR9'. + 'RdOmkzmP7DDpilfX3SzvRgQ/Vr1uiZplfsCBiVf03RJd140wgj'. + 'kmNqMtuYXcxyYmNWJdRoYwzpM9qRvGujuCmSR7q7ARY00/MiWk'. + 'sCnjkobNEm1+HknDZgAqR0GKU43+wxdu2hYzbsHU6AAAAABJRU'. + '5ErkJggg==' ; + + //========================================================== + // File: bs_lightred.png + //========================================================== + $this->imgdata_small[14][0]= 532 ; + $this->imgdata_small[14][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAA3l'. + 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. + 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. + 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. + 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. + 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. + 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. + 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGjoP2Nm+AAAAr0'. + 'lEQVR4nGNgIBaYiOk62imYwPnMkiIyso76yhJSzFARMxkRNk49'. + 'a3t5OW6oFk1LVkYOfWUHKxUXiEYzLS12DnN3VXkjIRtFsIiSk5'. + '6evqGqhYGKugAfWMRa1FpD2UHeQEXQRlgALCJur+rgbCUNFOAS'. + 'hqjRkZe3MpBTcwEKCEPMMTGSs3Xz8OQHCnBBHckt6OJpIyAMBD'. + 'wwN/MYc4H4LK4wNzMwmGrzcvFqmxIdDgDiHRT6VVQkrAAAAABJ'. + 'RU5ErkJggg==' ; + + //========================================================== + // File: bxs_lightred.png + //========================================================== + $this->imgdata_xsmall[0][0]= 432 ; + $this->imgdata_xsmall[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAA3l'. + 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. + 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. + 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. + 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. + 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. + 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. + 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKBOgGhWjAAAAS0'. + 'lEQVR4nGNgQAEmunYmEJaMCKe1vBxYzJKVQ9lKBSSupKdnaKGi'. + 'zgdkiqs6WKnYcIGYJnK2HvzCwmCNgi42wsLCECNMeXlNUY0HAL'. + 'DaB7Du8MiEAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bxs_bluegreen.png + //========================================================== + $this->imgdata_xsmall[1][0]= 397 ; + $this->imgdata_xsmall[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAvV'. + 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. + 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. + '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. + 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. + '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. + 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. + 'AJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKDVyF5Be'. + 'AAAASUlEQVR4nGNgQAFmYqJcEJaEOJ+UrD5YTJKFTZrfGCQuaq'. + 'glLWvMaQ5kqujo6hnbKIKYXPr68gp2dmCNJiZAlh3ECGsREWtU'. + '4wF1kwdpAHfnSwAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bxs_navy.png + //========================================================== + $this->imgdata_xsmall[2][0]= 353 ; + $this->imgdata_xsmall[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. + 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. + 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. + 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. + 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. + 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJxXO4axZAAAAR0'. + 'lEQVR4nGNgQAGskhKsEJaslIi8ijpYTJaDU1FVAyQuKSujoKKh'. + 'LQ5kSigpqWro6oOYrOoaWroGBmCNWiCWAdQwUVFWVOMBOp4GCJ'. + 's5S60AAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_gray.png + //========================================================== + $this->imgdata_xsmall[3][0]= 492 ; + $this->imgdata_xsmall[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABI1'. + 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. + 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. + 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. + 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. + 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. + 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. + '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. + 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. + 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEA'. + 'AAsRAX9kX5EAAAAHdElNRQfTAwkUKC74clmyAAAAQklEQVR4nG'. + 'NgQAVBYVCGt5dXYEQ0mOnp5h4QFgVmeri6+4dHxYMVeHoFRUTH'. + 'gTUFBIZBWAwMkZEx8bFQM2Lj0UwHANc/DV6yq/BiAAAAAElFTk'. + 'SuQmCC' ; + + //========================================================== + // File: bxs_graypurple.png + //========================================================== + $this->imgdata_xsmall[4][0]= 542 ; + $this->imgdata_xsmall[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABSl'. + 'BMVEX////////11P/MqdvKrNfAwMC+u7+9u7+4rr24lsi3rby3'. + 'lMe1rLq1o720q7i0oL20ksSzoryyqbaykMGxlb2wkL+vnbiujb'. + '2sjLuri7qpl7GoirWoibenmK2mla6mjLKmhrSllauki7CjhrCj'. + 'hLGihLChg6+ggq2fkqadkKOcfqqai6Gag6WYe6WXeqSWeaOTd6'. + 'CTd5+Rdp6RdZ6RdZ2Qg5eOc5qMcpiLcZeJb5WIbpOHbZKGbJGE'. + 'a4+CaY2AZ4t/Z4p/Zop/Zol+Zol7ZIZ6Y4V5YoR1ZH11X391Xn'. + '9zXX1yXXtxXHtvWnluWXhsV3VqVnNpVXJoVHFnU3BmUm9jUGth'. + 'VGdgTmheTGZcS2RcSmRaSWJYR19XRl5SQllRQlhQQVdPQFZOP1'. + 'VLPlFJO09IPE5IOk5FOEtEN0lDOEpDOElDNklCNkc/M0XhbrfD'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'EAAAsRAX9kX5EAAAAHdElNRQfTAwkUKCgREfyHAAAATUlEQVR4'. + 'nGNgQAEcIko8EBY3M5Ougy+IxSXMwmTsFsAHZMqrSRvZB0W7A5'. + 'k6FlYugXEZICaPr394Um4uSAFDRFRCbm4uxAihsDAhVOMBHT0L'. + 'hkeRpo8AAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_red.png + //========================================================== + $this->imgdata_xsmall[5][0]= 357 ; + $this->imgdata_xsmall[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. + 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. + 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. + 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. + 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. + 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIyjy5SVMAAAAS0'. + 'lEQVR4nGNgQAFsUpJsEJastIi8ijpYTJaDU0FVgxXIlJKVUVDR'. + '0BYHMiUUlVQ1dPVBTDZ1dS1dAwOQAgYtbSDLAGIEq6goK6rxAD'. + 'yXBg73lwGUAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: bxs_yellow.png + //========================================================== + $this->imgdata_xsmall[6][0]= 414 ; + $this->imgdata_xsmall[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAzF'. + 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. + 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. + 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. + 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. + 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. + '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. + 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAH'. + 'dElNRQfTAwkUIzoBXFQEAAAAS0lEQVR4nGNgQAFsDhJsEJaTo5'. + '2skj5YzMnSSk7ZwBzIlOSUklPiMxYHMnW4FXT5VNVBTDZeXiNV'. + 'QUGQAgYBYyBLEGIEq5gYK6rxAH4kBmHBaMQQAAAAAElFTkSuQm'. + 'CC' ; + + //========================================================== + // File: bxs_greenblue.png + //========================================================== + $this->imgdata_xsmall[7][0]= 410 ; + $this->imgdata_xsmall[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAxl'. + 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. + '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. + '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. + 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. + 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. + 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. + 'dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfT'. + 'AwkUJy5/6kV9AAAATUlEQVR4nGNgQAGCyuyCEJaGugKHviVYzF'. + 'hO3sxCWwDIVNLTM9PXtpEGMhW12Cy0DR1ATEFLSxZ7BweQAgYd'. + 'HUMHBweIEQKiogKoxgMAo/4H5AfSehsAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_purple.png + //========================================================== + $this->imgdata_xsmall[8][0]= 364 ; + $this->imgdata_xsmall[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAnF'. + 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. + 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. + 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. + 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. + 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIj'. + 'mBTjT/AAAASUlEQVR4nGNgQAGskhKsEJaCrJiSuhZYTEFASFlD'. + 'GyQuqSCnrK6tJwpkiquoamgbGIGYrFpaugbGxmCNunpAljHECB'. + 'ZBQRZU4wFSMAZsXeM71AAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bxs_green.png + //========================================================== + $this->imgdata_xsmall[9][0]= 370 ; + $this->imgdata_xsmall[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAn1'. + 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. + '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. + 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. + '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. + 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. + 'AIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAw'. + 'kUKBrZxq0HAAAATElEQVR4nGNgQAGccrIcEJaivISyhjaIxa7I'. + 'I6CiqcMKZMopKqho6OhLA5kyqmqaOobGICartraeoYkJSAGDnj'. + '6QZQIxgk1Skg3VeABlVgbItqEBUwAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bxs_darkgreen.png + //========================================================== + $this->imgdata_xsmall[10][0]= 563 ; + $this->imgdata_xsmall[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABX1'. + 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. + 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. + 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. + 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. + '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. + 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. + 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. + 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. + 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. + 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. + 'RQfTAwkUKCFozUQjAAAATUlEQVR4nGNgQAGcoqrcEJYQB5OhSw'. + 'CIxSXGwWThGcIDZCppK5o7hyV6AZl6NnbuoSmFICZ3YHB0RkkJ'. + 'SAFDbEJaSUkJxAjeyEheVOMBQj4MOEkWew4AAAAASUVORK5CYI'. + 'I=' ; + + //========================================================== + // File: bxs_cyan.png + //========================================================== + $this->imgdata_xsmall[11][0]= 530 ; + $this->imgdata_xsmall[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABPl'. + 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. + '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. + 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. + '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. + 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. + '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. + '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. + 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. + 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAA'. + 'AHdElNRQfTAwkUKQFKuFWqAAAATUlEQVR4nGNgQAGsUjJsEJaR'. + 'grC5qz9YzIiL28YriB3IlDZRsnYNiZUDMmXtHT2CE9JBTDb/wI'. + 'jkzEyQAoaomMTMzEyIERzy8hyoxgMAN2MLVPW0f4gAAAAASUVO'. + 'RK5CYII=' ; + + //========================================================== + // File: bxs_orange.png + //========================================================== + $this->imgdata_xsmall[12][0]= 572 ; + $this->imgdata_xsmall[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABaF'. + 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. + 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. + 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. + 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. + '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. + 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. + 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. + 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. + 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. + 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. + 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9k'. + 'X5EAAAAHdElNRQfTAwkUJBSSy88MAAAATUlEQVR4nGNgQAGqwo'. + 'paEBYPJ4eKezCIpc7HwmrqG6ENZMpLihm6RaWEAZl6Vo7ekRnF'. + 'IKZWSHhcTnk5SAFDfFJWeXk5xAjj1FRjVOMBeFwNcWYSLjsAAA'. + 'AASUVORK5CYII=' ; + + //========================================================== + // File: bxs_lightblue.png + //========================================================== + $this->imgdata_xsmall[13][0]= 554 ; + $this->imgdata_xsmall[13][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABVl'. + 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. + 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. + '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. + 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. + 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. + 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. + 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. + 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. + 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. + 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJziL'. + 'PvAsAAAATUlEQVR4nGNgQAHsQgqcEJYgG5Oegy+IxSHOxmTiFs'. + 'gFZMprKBnbB8e7AplaFlbOQUl5ICanX0BEWmEhSAFDVGxKYWEh'. + 'xAjusDBuVOMBJO8LrFHRAykAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bxs_darkgray.png + //========================================================== + $this->imgdata_xsmall[14][0]= 574 ; + $this->imgdata_xsmall[14][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABm'. + 'JLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAB'. + 'iElEQVR42k3QPU8TYRwA8P//ebkXrgdIColXRAOEkJqbaExMut'. + 'DBhE1GNjYHPg+DG6ODiU6QOLjVxITBcFKBYCstlAC2Bz17fe76'. + 'vLD6+wg/1FpTRFR5lpaub/u1eGBGaAT4HneD4OlXx7avtDYUjT'. + 'HQabd2Ti8e3vVSKzxrtHS32wIpFVldno22Nqvvg2Bhl0gp/aNm'. + 'vJ3qqXAtLIva+ks1H0wqlSXi4+d6+OFTfRsAfHJx2d1od24rZP'. + 'xP2HzopINr1mkesX7ccojqif0v9crxWXODZTno3+dNGA7uWLsd'. + 'mUYU4fHJCViMG9umLBmM4L6fagZGg9QKfjZ+Qfy3C3G/B3mugF'. + 'IHHNcDf64E3KJALApk2p8CSolUUqLjFkyxOGMsTtFyJ+Wz57NQ'. + '8DghS4sLB0svioeZZo7nPhFoUKZDIVFbglkTTnl5/rC8snjAkJ'. + 'Bk/XV5LxHC/v7tR8jzTFPbg8LENK9WX0Vv31T2AEmCSmlKCCoh'. + 'ROnP1U1tPFYjJBRcbtzSf+GPsFTAQBq1n4AAAABKdEVYdHNpZ2'. + '5hdHVyZQBiYzYyMDIyNjgwYThjODMyMmUxNjk0NWUzZjljOGFh'. + 'N2VmZWFhMjA4OTE2ZjkwOTdhZWE1MzYyMjk0MWRkM2I5EqaPDA'. + 'AAAABJRU5ErkJggg==' ; + } +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/imgdata_bevels.inc.php b/ext/jpgraph-3.0.7/src/imgdata_bevels.inc.php index 5a33154..947e210 100644 --- a/ext/jpgraph-3.0.7/src/imgdata_bevels.inc.php +++ b/ext/jpgraph-3.0.7/src/imgdata_bevels.inc.php @@ -1,104 +1,104 @@ - 'imgdata'); - - protected $colors = array('green','purple','orange','red','yellow'); - protected $index = array('green'=>1,'purple'=>4,'orange'=>2,'red'=>0,'yellow'=>3); - protected $maxidx = 4 ; - - protected $imgdata ; - - function __construct() { - //========================================================== - // File: bullets_balls_red_013.png - //========================================================== - $this->imgdata[0][0]= 337 ; - $this->imgdata[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. - 'BMVEX////////27t/f3+LFwcmNxMuxm62DmqKth1VpZmIWg6fv'. - 'HCa7K0BwMEytCjFnIyUlEBg9vhQvAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. - 'RQfTAxcBNhk+pYJVAAAAl0lEQVR4nE2Q2xLDIAgFHUWBKJf//9'. - 'oekmbafVDZARRbK/pYTKP9WNcNv64zzUdd9BjmrgnsVXRNSzO3'. - 'CJ5ahdhy0XKQkxld1kxb45j7dp0x2lBNOyVgQpMaoadX7Hs7zr'. - 'P1yKj47DKBnKaBKiSAkNss7O6PkMx6kIgYXISQJpcZCqdY6KR+'. - 'J1PkS5Xob/h7MNz8x6D3fz5DKQjpkZOBYAAAAABJRU5ErkJggg'. - '==' ; - - //========================================================== - // File: bullets_balls_green_013.png - //========================================================== - $this->imgdata[1][0]= 344 ; - $this->imgdata[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. - 'BMVEX////////27t/e3+K3vriUub/Dm18j4xc3ob10k0ItqQlU'. - 'e5JBmwpxY1ENaKBgUh0iHgwsSre9AAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. - 'RQfTAxcBNTfJXtxZAAAAnklEQVR4nE2QWY4EMQhDUVhSIRC4/2'. - 'kbaqLp9p+f2AxAayAzDfiK9znPORuvH0x8Ss9z6I9sHp6tcxE9'. - 'nLmWmebmt5F5p2AR0+C9AWpLBjXRaZsCAT3SqklVp0YkAWaGtd'. - 'c5Z41/STYpPzW7BjyiRrwkVmQto/Cw9tNEMvsgcekyCyFPboIu'. - 'IsuXiKffYB4NK4r/h6d4g9HPPwCR7i8+GscIiiaonUAAAAAASU'. - 'VORK5CYII=' ; - - //========================================================== - // File: bullets_balls_oy_035.png - //========================================================== - $this->imgdata[2][0]= 341 ; - $this->imgdata[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. - 'BMVEX////////27t/f3+K5tbqNwcjnkjXjbxR2i5anfEoNkbis'. - 'PBxpU0sZbZejKgdqIRIlERIwYtkYAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. - 'RQfTAxcBNgK0wEu5AAAAm0lEQVR4nE3QVxIEIQgEUErAgTHA/U'. - '+7zbipf9RXgoGo0liMmX6RdSPLPtZM9F4LuuSIaZtZWffiU6Iz'. - 'Y8SOMF0NogBj30ioGRGLZgiPvce1TbIRz6oBQEbOFGK0rIoxrn'. - '5hDomMA1cfGRCaRVhjS3gkzheM+4HtnlkXcvdZhWG4qZawewe6'. - '9Jnz/TKLB/ML6HUepn//QczazuwFO/0Ivpolhi4AAAAASUVORK'. - '5CYII=' ; - - //========================================================== - // File: bullets_balls_oy_036.png - //========================================================== - $this->imgdata[3][0]= 340 ; - $this->imgdata[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. - 'BMVEX////////27t/e3+LO3hfYzz65ubiNwci6uQ12ipadgVGa'. - 'fwsNkbhnVkcaZ5dwSA8lFg7CEepmAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. - 'RQfTAxcCBySi1nevAAAAjElEQVR4nFXPWw7EIAgFUNMoCMhj/6'. - 'staKczc/2RkwjS2glQ+w3YytgXCXCZpRo8gJdGxZadJws13CUP'. - '4SZI4MYiUxypeiGGw1XShVBTNN9kLXP2GRrZPFvKgd7z/sqGGV'. - '7C7r7r3l09alYN3iA8Yn+ImdVrNoEeSRqJPAaHfhZzLYwXstdZ'. - 'rP3n2bvdAI4INwtihiwAAAAASUVORK5CYII=' ; - - //========================================================== - // File: bullets_balls_pp_019.png - //========================================================== - $this->imgdata[4][0]= 334 ; - $this->imgdata[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. - 'BMVEX////+/v7i4eO/w8eHxcvKroNVormtfkjrMN2BeXQrepPc'. - 'Esy4IL+OFaR7F25LHF8mFRh5XXtUAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. - 'RQfTAxcBNgkjEpIxAAAAlElEQVR4nE2QAQ7FIAhDDTAVndL7n3'. - 'ZV/7JfEwMvFIWUlkTMVNInbVv5ZeJqG7Smh2QTBwJBpsdizAZP'. - '5NyW0awhK8kYodnZxS6ECvPRp2sI+y7PBv1mN02KH7h77QCJ8D'. - '4VvY5NUgEmCwj6ZMzHtJRgRSXwC1gfcqJJH0GBnSnK1kUQ72DY'. - 'CPBv+MCS/e0jib77eQAJxwiEWm7hFwAAAABJRU5ErkJggg==' ; - - } -} - - + 'imgdata'); + + protected $colors = array('green','purple','orange','red','yellow'); + protected $index = array('green'=>1,'purple'=>4,'orange'=>2,'red'=>0,'yellow'=>3); + protected $maxidx = 4 ; + + protected $imgdata ; + + function __construct() { + //========================================================== + // File: bullets_balls_red_013.png + //========================================================== + $this->imgdata[0][0]= 337 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/f3+LFwcmNxMuxm62DmqKth1VpZmIWg6fv'. + 'HCa7K0BwMEytCjFnIyUlEBg9vhQvAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNhk+pYJVAAAAl0lEQVR4nE2Q2xLDIAgFHUWBKJf//9'. + 'oekmbafVDZARRbK/pYTKP9WNcNv64zzUdd9BjmrgnsVXRNSzO3'. + 'CJ5ahdhy0XKQkxld1kxb45j7dp0x2lBNOyVgQpMaoadX7Hs7zr'. + 'P1yKj47DKBnKaBKiSAkNss7O6PkMx6kIgYXISQJpcZCqdY6KR+'. + 'J1PkS5Xob/h7MNz8x6D3fz5DKQjpkZOBYAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: bullets_balls_green_013.png + //========================================================== + $this->imgdata[1][0]= 344 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/e3+K3vriUub/Dm18j4xc3ob10k0ItqQlU'. + 'e5JBmwpxY1ENaKBgUh0iHgwsSre9AAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNTfJXtxZAAAAnklEQVR4nE2QWY4EMQhDUVhSIRC4/2'. + 'kbaqLp9p+f2AxAayAzDfiK9znPORuvH0x8Ss9z6I9sHp6tcxE9'. + 'nLmWmebmt5F5p2AR0+C9AWpLBjXRaZsCAT3SqklVp0YkAWaGtd'. + 'c5Z41/STYpPzW7BjyiRrwkVmQto/Cw9tNEMvsgcekyCyFPboIu'. + 'IsuXiKffYB4NK4r/h6d4g9HPPwCR7i8+GscIiiaonUAAAAAASU'. + 'VORK5CYII=' ; + + //========================================================== + // File: bullets_balls_oy_035.png + //========================================================== + $this->imgdata[2][0]= 341 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/f3+K5tbqNwcjnkjXjbxR2i5anfEoNkbis'. + 'PBxpU0sZbZejKgdqIRIlERIwYtkYAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNgK0wEu5AAAAm0lEQVR4nE3QVxIEIQgEUErAgTHA/U'. + '+7zbipf9RXgoGo0liMmX6RdSPLPtZM9F4LuuSIaZtZWffiU6Iz'. + 'Y8SOMF0NogBj30ioGRGLZgiPvce1TbIRz6oBQEbOFGK0rIoxrn'. + '5hDomMA1cfGRCaRVhjS3gkzheM+4HtnlkXcvdZhWG4qZawewe6'. + '9Jnz/TKLB/ML6HUepn//QczazuwFO/0Ivpolhi4AAAAASUVORK'. + '5CYII=' ; + + //========================================================== + // File: bullets_balls_oy_036.png + //========================================================== + $this->imgdata[3][0]= 340 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/e3+LO3hfYzz65ubiNwci6uQ12ipadgVGa'. + 'fwsNkbhnVkcaZ5dwSA8lFg7CEepmAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. + 'RQfTAxcCBySi1nevAAAAjElEQVR4nFXPWw7EIAgFUNMoCMhj/6'. + 'staKczc/2RkwjS2glQ+w3YytgXCXCZpRo8gJdGxZadJws13CUP'. + '4SZI4MYiUxypeiGGw1XShVBTNN9kLXP2GRrZPFvKgd7z/sqGGV'. + '7C7r7r3l09alYN3iA8Yn+ImdVrNoEeSRqJPAaHfhZzLYwXstdZ'. + 'rP3n2bvdAI4INwtihiwAAAAASUVORK5CYII=' ; + + //========================================================== + // File: bullets_balls_pp_019.png + //========================================================== + $this->imgdata[4][0]= 334 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////+/v7i4eO/w8eHxcvKroNVormtfkjrMN2BeXQrepPc'. + 'Esy4IL+OFaR7F25LHF8mFRh5XXtUAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNgkjEpIxAAAAlElEQVR4nE2QAQ7FIAhDDTAVndL7n3'. + 'ZV/7JfEwMvFIWUlkTMVNInbVv5ZeJqG7Smh2QTBwJBpsdizAZP'. + '5NyW0awhK8kYodnZxS6ECvPRp2sI+y7PBv1mN02KH7h77QCJ8D'. + '4VvY5NUgEmCwj6ZMzHtJRgRSXwC1gfcqJJH0GBnSnK1kUQ72DY'. + 'CPBv+MCS/e0jib77eQAJxwiEWm7hFwAAAABJRU5ErkJggg==' ; + + } +} + + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/imgdata_diamonds.inc.php b/ext/jpgraph-3.0.7/src/imgdata_diamonds.inc.php index ca68c81..fae3b9a 100644 --- a/ext/jpgraph-3.0.7/src/imgdata_diamonds.inc.php +++ b/ext/jpgraph-3.0.7/src/imgdata_diamonds.inc.php @@ -1,177 +1,177 @@ -'imgdata'); - protected $colors = array('lightblue','darkblue','gray', - 'blue','pink','purple','red','yellow'); - protected $index = array('lightblue' =>7,'darkblue'=>2,'gray'=>6, - 'blue'=>4,'pink'=>1,'purple'=>5,'red'=>0,'yellow'=>3); - - protected $maxidx = 7 ; - protected $imgdata ; - - function __construct() { - //========================================================== - // File: diam_red.png - //========================================================== - $this->imgdata[0][0]= 668 ; - $this->imgdata[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. - 'BMVEX///////+cAAD/AADOAABjAABrAADWGBjOCAj/CAj/GBj/'. - 'EBCcCAiMOTl7KSl7ISFzGBilGBjOEBBrCAjv5+eMQkK1QkKtMT'. - 'GtKSnWKSn/KSlzEBCcEBDexsb/tbXOe3ucWlqcUlKUSkr/e3vn'. - 'a2u9UlL/a2uEMTHeUlLeSkqtOTn/UlL/SkrWOTn/QkL/OTmlIS'. - 'H/MTH/ISH39/f/9/f35+fezs7/5+fvzs7WtbXOra3nvb3/zs7G'. - 'nJzvtbXGlJTepaW9jIy1hITWlJS1e3uta2ulY2P/lJTnhITne3'. - 'vGY2O9Wlr/c3PeY2O1Skr/Y2P/WlreQkLWISGlEBCglEUaAAAA'. - 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. - 'sSAdLdfvwAAAAHdElNRQfTAwsWEw5WI4qnAAABGUlEQVR4nHXQ'. - '1XLDMBAFUKUCM1NiO8zcpIxpp8z0//9SWY7b2LHv6EU6s1qtAN'. - 'iMBAojLPkigpJvogKC4pxDuQipjanlICXof1RQDkYEF21mKIfg'. - '/GGKtjAmOKt9oSyuCU7OhyiDCQnjowGfRnooCJIkiWJvv8NxnG'. - 'nyNAwFcekvZpPP3mu7Vrp8fOq8DYbTyjdnAvBj7Jbd7nP95urs'. - '+MC2D6unF+Cu0VJULQBAlsOQuueN3Hrp2nGUvqppemBZ0aU7Se'. - 'SXvYZFMKaLJn7MH3btJmZEMEmGSOreqy0SI/4ffo3uiUOYEACy'. - 'OFopmNWlP5uZd9uPWmUoxvK9ilO9NtBo6mS7KkZD0fOJYqgGBU'. - 'S/T7OKCAA9tfsFOicXcbxt29cAAAAASUVORK5CYII=' ; - - //========================================================== - // File: diam_pink.png - //========================================================== - $this->imgdata[1][0]= 262 ; - $this->imgdata[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. - 'BMVEX///+AgID/M5n/Zpn/zMz/mZn1xELhAAAAAXRSTlMAQObY'. - 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. - 'AHdElNRQfTAwsWEi3tX8qUAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. - 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. - '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. - 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. - '==' ; - - //========================================================== - // File: diam_blue.png - //========================================================== - $this->imgdata[2][0]= 662 ; - $this->imgdata[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA+V'. - 'BMVEX///+AgIAAAJwAAP8AAM4AAGMAAGsQEP8YGHMQEHMYGP8Q'. - 'EKUICJwICM5KSpQxMYQpKXsYGNYQEM4ICGsICP97e85aWpw5OY'. - 'xSUv85ObVCQt4xMa0pKa0hIaUpKf+9vd6EhLVra+dzc/9SUr1r'. - 'a/9aWt5SUt5CQrVaWv9KSv8hIXs5Of8xMf8pKdYhIdYYGKUhIf'. - '/Ozs739//v7/fn5+/v7//n5/fW1ufOzufOzu/W1v+trc69veel'. - 'pc6trd6UlMa9vf+MjL21tfe1tf+UlNZzc61ra6Wlpf+EhOeMjP'. - '9ra8ZSUpyEhP9CQoxKSrVCQv85Od4xMdYQENZnJhlWAAAAAXRS'. - 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. - 'LdfvwAAAAHdElNRQfTAwsWEx3Snct5AAABFklEQVR4nHXR5XbD'. - 'IBgGYM6AuHsaqbvOfeuknev9X8xISbplSd5/8JyXwwcA/I0AKm'. - 'PFchVBdvKNKggKQx2VIoRwMZihMiQE49YUlWBCcPL0hYq4ITh+'. - 'qKECUoLDZWqoQNA766F/mJHlHXblPJJNiyURhM5eU9cNw5BlmS'. - 'IrLOLxhzfotF7vwO2j3ez2ap/TmW4AIM7DoN9+tu+vLk6Pdg9O'. - '6ufXjfXLm6pxPACSJIpRFAa+/26DhuK6qjbiON40k0N3skjOvm'. - 'NijBmchF5mi+1jhQqDmWyIzPp1hUlrv8On5l+6mMm1tigFNyrt'. - '5R97g+FKKyGKkTNKesXPJTZXOFIrUoKiypcTQVHjK4g8H2dWEQ'. - 'B8bvUDLSQXSr41rmEAAAAASUVORK5CYII=' ; - - //========================================================== - // File: diam_yellow.png - //========================================================== - $this->imgdata[3][0]= 262 ; - $this->imgdata[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. - 'BMVEX///+AgIBmMwCZZgD/zADMmQD/QLMZAAAAAXRSTlMAQObY'. - 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. - 'AHdElNRQfTAwsWEwcv/zIDAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. - 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. - '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. - 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. - '==' ; - - //========================================================== - // File: diam_lightblue.png - //========================================================== - $this->imgdata[4][0]= 671 ; - $this->imgdata[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/1'. - 'BMVEX///+AgIAAnP8A//8Azv8AY/8Aa/8I//8Y1v8Izv8Y//8Q'. - '//8InP8Qzv8Ypf85jP8he/8Yc/8Ia/8pe/8p//8p1v9Ctf8xrf'. - '8prf8QnP8Qc/9CjP+1//97//9r//9S//9K//9C//85//8x//8h'. - '//9r5/9K3v9S3v851v97zv9Svf85rf8hpf/G3v9SnP9anP9KlP'. - '8xhP/n7//v7+f3///n///O//+U//9z//9j//9a//975/9C3v8h'. - '1v+E5/+17/9j3v/O7//n9/+95/+l3v9jxv+U1v8Qpf9avf9Ktf'. - '+Uxv+11v97tf9rrf+cxv+Mvf9jpf+tzv+Etf/O3v/39/8Akkxr'. - 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. - 'IAAAsSAdLdfvwAAAAHdElNRQfTAwsWEiHk6Ya/AAABGUlEQVR4'. - 'nHXQ13KDMBAF0J2o0E01GHDvJa7p3em95/+/JQJMYjDc0Yt0Zr'. - 'VaAaxHgtxwbSGPkGQpOIeQ2ORxJiJmNWYZyAhZR0WcgQGhViU0'. - 'nEGoedDHGxgRapRPcRpXhOr7XZzCmLjaXk9IIjvkOEmSRLG62+'. - 'F5XlEElhA5sW21GvXj6mGlDBfnJ51lr9svnvEKwH1hu2QPbwd3'. - 'N9eXVzuL7/Hn29frdKaamgcgy67L3HFG9gDefV+dm5qme4YRXL'. - 'oVR374mRqUELZYosf84XAxISFRQuMh4rrH8YxGSP6HX6H97NNQ'. - 'KEAaR08qCeuSnx2a8zIPWqUowtKHSRK91rAw0elmVYQFVc8mhq'. - '7p5RD7Ps3IIwA9sfsFxFUX6eZ4Zh4AAAAASUVORK5CYII=' ; - - //========================================================== - // File: diam_purple.png - //========================================================== - $this->imgdata[5][0]= 657 ; - $this->imgdata[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. - 'BMVEX///////8xAP/OAP+cAP9jAP9rAP+cCP85CP/OEP9SKf/O'. - 'CP9CEP9zGP9rCP+lGP/WOf/WIf9KIf9jOf+MQv+EMf97If9zEP'. - '+1Sv+lIf/ne//eUv/na//n5//Oxv/Wzv+chP9zUv97Wv9rQv9a'. - 'Mf9KGP/v5/+te/97Kf+9Y/+tOf+tKf+lEP/vtf/WMf/WKf/v7+'. - 'f39/+tnP+9rf9rSv9jQv9CGP+ljP+EY//Gtf+tlP+Ma/9zSv/e'. - 'zv+UUv+9lP+cWv+lY/+cUv+MOf+EKf+UQv/Opf/OhP/Ga/+1Qv'. - '/Oe/+9Uv/ntf/eWv/eSv/WGP/3zv/vlP/WEP//9/+pL4oHAAAA'. - 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. - 'sSAdLdfvwAAAAHdElNRQfTAwsWEjX+M1LCAAABDklEQVR4nHXQ'. - '1bLDIBAGYFqIEW+ksbr7cXd3ff93OUCamdOE/Mxw882yywLwPz'. - '+gNKotlRFUVnNUQlCxTMRFCKEdE+MgpJaEiIOU4DKaoSIygtb3'. - 'FBUQrm3xjPK4JvXjK0A5hFniYSBtIilQVYUm+X0KTVNiYah+2q'. - 'ulFb8nUbSovD2+TCavwXQWmnMA6ro+di+uR5cPzfPhVqPV3N1p'. - 'n3b3+rimAWAYhP3xnXd7P6oc9vadPsa1wYEs00dFQRAFehlX21'. - '25Sg9NOgwF5jeNTjVL9om0TjDc1lmeCKZ17nFPzhPtSRt6J06R'. - 'WKUoeG3MoXRa/wjLHGLodwZcotPqjsYngnWslRBZH91hWTbpD2'. - 'EdF1ECWW1SAAAAAElFTkSuQmCC' ; - - //========================================================== - // File: diam_gray.png - //========================================================== - $this->imgdata[6][0]= 262 ; - $this->imgdata[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. - 'BMVEX//////wAzMzNmZmbMzMyZmZlq4Qo5AAAAAXRSTlMAQObY'. - 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. - 'AHdElNRQfTAwsWExZFTxLxAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. - 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. - '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. - 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. - '==' ; - - //========================================================== - // File: diam_blgr.png - //========================================================== - $this->imgdata[7][0]= 262 ; - $this->imgdata[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. - 'BMVEX///+AgIBmzP9m///M//+Z//8hMmBVAAAAAXRSTlMAQObY'. - 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. - 'AHdElNRQfTAwsWEwCxm6egAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. - 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. - '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. - 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. - '==' ; - } -} - +'imgdata'); + protected $colors = array('lightblue','darkblue','gray', + 'blue','pink','purple','red','yellow'); + protected $index = array('lightblue' =>7,'darkblue'=>2,'gray'=>6, + 'blue'=>4,'pink'=>1,'purple'=>5,'red'=>0,'yellow'=>3); + + protected $maxidx = 7 ; + protected $imgdata ; + + function __construct() { + //========================================================== + // File: diam_red.png + //========================================================== + $this->imgdata[0][0]= 668 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. + 'BMVEX///////+cAAD/AADOAABjAABrAADWGBjOCAj/CAj/GBj/'. + 'EBCcCAiMOTl7KSl7ISFzGBilGBjOEBBrCAjv5+eMQkK1QkKtMT'. + 'GtKSnWKSn/KSlzEBCcEBDexsb/tbXOe3ucWlqcUlKUSkr/e3vn'. + 'a2u9UlL/a2uEMTHeUlLeSkqtOTn/UlL/SkrWOTn/QkL/OTmlIS'. + 'H/MTH/ISH39/f/9/f35+fezs7/5+fvzs7WtbXOra3nvb3/zs7G'. + 'nJzvtbXGlJTepaW9jIy1hITWlJS1e3uta2ulY2P/lJTnhITne3'. + 'vGY2O9Wlr/c3PeY2O1Skr/Y2P/WlreQkLWISGlEBCglEUaAAAA'. + 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. + 'sSAdLdfvwAAAAHdElNRQfTAwsWEw5WI4qnAAABGUlEQVR4nHXQ'. + '1XLDMBAFUKUCM1NiO8zcpIxpp8z0//9SWY7b2LHv6EU6s1qtAN'. + 'iMBAojLPkigpJvogKC4pxDuQipjanlICXof1RQDkYEF21mKIfg'. + '/GGKtjAmOKt9oSyuCU7OhyiDCQnjowGfRnooCJIkiWJvv8NxnG'. + 'nyNAwFcekvZpPP3mu7Vrp8fOq8DYbTyjdnAvBj7Jbd7nP95urs'. + '+MC2D6unF+Cu0VJULQBAlsOQuueN3Hrp2nGUvqppemBZ0aU7Se'. + 'SXvYZFMKaLJn7MH3btJmZEMEmGSOreqy0SI/4ffo3uiUOYEACy'. + 'OFopmNWlP5uZd9uPWmUoxvK9ilO9NtBo6mS7KkZD0fOJYqgGBU'. + 'S/T7OKCAA9tfsFOicXcbxt29cAAAAASUVORK5CYII=' ; + + //========================================================== + // File: diam_pink.png + //========================================================== + $this->imgdata[1][0]= 262 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgID/M5n/Zpn/zMz/mZn1xELhAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEi3tX8qUAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: diam_blue.png + //========================================================== + $this->imgdata[2][0]= 662 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA+V'. + 'BMVEX///+AgIAAAJwAAP8AAM4AAGMAAGsQEP8YGHMQEHMYGP8Q'. + 'EKUICJwICM5KSpQxMYQpKXsYGNYQEM4ICGsICP97e85aWpw5OY'. + 'xSUv85ObVCQt4xMa0pKa0hIaUpKf+9vd6EhLVra+dzc/9SUr1r'. + 'a/9aWt5SUt5CQrVaWv9KSv8hIXs5Of8xMf8pKdYhIdYYGKUhIf'. + '/Ozs739//v7/fn5+/v7//n5/fW1ufOzufOzu/W1v+trc69veel'. + 'pc6trd6UlMa9vf+MjL21tfe1tf+UlNZzc61ra6Wlpf+EhOeMjP'. + '9ra8ZSUpyEhP9CQoxKSrVCQv85Od4xMdYQENZnJhlWAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwsWEx3Snct5AAABFklEQVR4nHXR5XbD'. + 'IBgGYM6AuHsaqbvOfeuknev9X8xISbplSd5/8JyXwwcA/I0AKm'. + 'PFchVBdvKNKggKQx2VIoRwMZihMiQE49YUlWBCcPL0hYq4ITh+'. + 'qKECUoLDZWqoQNA766F/mJHlHXblPJJNiyURhM5eU9cNw5BlmS'. + 'IrLOLxhzfotF7vwO2j3ez2ap/TmW4AIM7DoN9+tu+vLk6Pdg9O'. + '6ufXjfXLm6pxPACSJIpRFAa+/26DhuK6qjbiON40k0N3skjOvm'. + 'NijBmchF5mi+1jhQqDmWyIzPp1hUlrv8On5l+6mMm1tigFNyrt'. + '5R97g+FKKyGKkTNKesXPJTZXOFIrUoKiypcTQVHjK4g8H2dWEQ'. + 'B8bvUDLSQXSr41rmEAAAAASUVORK5CYII=' ; + + //========================================================== + // File: diam_yellow.png + //========================================================== + $this->imgdata[3][0]= 262 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgIBmMwCZZgD/zADMmQD/QLMZAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEwcv/zIDAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: diam_lightblue.png + //========================================================== + $this->imgdata[4][0]= 671 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/1'. + 'BMVEX///+AgIAAnP8A//8Azv8AY/8Aa/8I//8Y1v8Izv8Y//8Q'. + '//8InP8Qzv8Ypf85jP8he/8Yc/8Ia/8pe/8p//8p1v9Ctf8xrf'. + '8prf8QnP8Qc/9CjP+1//97//9r//9S//9K//9C//85//8x//8h'. + '//9r5/9K3v9S3v851v97zv9Svf85rf8hpf/G3v9SnP9anP9KlP'. + '8xhP/n7//v7+f3///n///O//+U//9z//9j//9a//975/9C3v8h'. + '1v+E5/+17/9j3v/O7//n9/+95/+l3v9jxv+U1v8Qpf9avf9Ktf'. + '+Uxv+11v97tf9rrf+cxv+Mvf9jpf+tzv+Etf/O3v/39/8Akkxr'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'IAAAsSAdLdfvwAAAAHdElNRQfTAwsWEiHk6Ya/AAABGUlEQVR4'. + 'nHXQ13KDMBAF0J2o0E01GHDvJa7p3em95/+/JQJMYjDc0Yt0Zr'. + 'VaAaxHgtxwbSGPkGQpOIeQ2ORxJiJmNWYZyAhZR0WcgQGhViU0'. + 'nEGoedDHGxgRapRPcRpXhOr7XZzCmLjaXk9IIjvkOEmSRLG62+'. + 'F5XlEElhA5sW21GvXj6mGlDBfnJ51lr9svnvEKwH1hu2QPbwd3'. + 'N9eXVzuL7/Hn29frdKaamgcgy67L3HFG9gDefV+dm5qme4YRXL'. + 'oVR374mRqUELZYosf84XAxISFRQuMh4rrH8YxGSP6HX6H97NNQ'. + 'KEAaR08qCeuSnx2a8zIPWqUowtKHSRK91rAw0elmVYQFVc8mhq'. + '7p5RD7Ps3IIwA9sfsFxFUX6eZ4Zh4AAAAASUVORK5CYII=' ; + + //========================================================== + // File: diam_purple.png + //========================================================== + $this->imgdata[5][0]= 657 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. + 'BMVEX///////8xAP/OAP+cAP9jAP9rAP+cCP85CP/OEP9SKf/O'. + 'CP9CEP9zGP9rCP+lGP/WOf/WIf9KIf9jOf+MQv+EMf97If9zEP'. + '+1Sv+lIf/ne//eUv/na//n5//Oxv/Wzv+chP9zUv97Wv9rQv9a'. + 'Mf9KGP/v5/+te/97Kf+9Y/+tOf+tKf+lEP/vtf/WMf/WKf/v7+'. + 'f39/+tnP+9rf9rSv9jQv9CGP+ljP+EY//Gtf+tlP+Ma/9zSv/e'. + 'zv+UUv+9lP+cWv+lY/+cUv+MOf+EKf+UQv/Opf/OhP/Ga/+1Qv'. + '/Oe/+9Uv/ntf/eWv/eSv/WGP/3zv/vlP/WEP//9/+pL4oHAAAA'. + 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. + 'sSAdLdfvwAAAAHdElNRQfTAwsWEjX+M1LCAAABDklEQVR4nHXQ'. + '1bLDIBAGYFqIEW+ksbr7cXd3ff93OUCamdOE/Mxw882yywLwPz'. + '+gNKotlRFUVnNUQlCxTMRFCKEdE+MgpJaEiIOU4DKaoSIygtb3'. + 'FBUQrm3xjPK4JvXjK0A5hFniYSBtIilQVYUm+X0KTVNiYah+2q'. + 'ulFb8nUbSovD2+TCavwXQWmnMA6ro+di+uR5cPzfPhVqPV3N1p'. + 'n3b3+rimAWAYhP3xnXd7P6oc9vadPsa1wYEs00dFQRAFehlX21'. + '25Sg9NOgwF5jeNTjVL9om0TjDc1lmeCKZ17nFPzhPtSRt6J06R'. + 'WKUoeG3MoXRa/wjLHGLodwZcotPqjsYngnWslRBZH91hWTbpD2'. + 'EdF1ECWW1SAAAAAElFTkSuQmCC' ; + + //========================================================== + // File: diam_gray.png + //========================================================== + $this->imgdata[6][0]= 262 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX//////wAzMzNmZmbMzMyZmZlq4Qo5AAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWExZFTxLxAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + + //========================================================== + // File: diam_blgr.png + //========================================================== + $this->imgdata[7][0]= 262 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgIBmzP9m///M//+Z//8hMmBVAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEwCxm6egAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + } +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/imgdata_pushpins.inc.php b/ext/jpgraph-3.0.7/src/imgdata_pushpins.inc.php index 97b38e5..9e49d15 100644 --- a/ext/jpgraph-3.0.7/src/imgdata_pushpins.inc.php +++ b/ext/jpgraph-3.0.7/src/imgdata_pushpins.inc.php @@ -1,517 +1,517 @@ - 'imgdata_small', - MARK_IMG_SPUSHPIN => 'imgdata_small', - MARK_IMG_LPUSHPIN => 'imgdata_large'); - - protected $colors = array('blue','green','orange','pink','red'); - protected $index = array('red' => 0, 'orange' => 1, 'pink' => 2, 'blue' => 3, 'green' => 4 ) ; - protected $maxidx = 4 ; - protected $imgdata_large, $imgdata_small ; - - function __construct() { - - // The anchor should be where the needle "hits" the paper - // (bottom left corner) - $this->anchor_x = 0; - $this->anchor_y = 1; - - //========================================================== - // File: ppl_red.png - //========================================================== - $this->imgdata_large[0][0]= 2490 ; - $this->imgdata_large[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMKBh4Ryh89CgAACUdJREFUeJy9mNtTFFcexz+/7p'. - '4Lw1wZJKDGCAwmDAqUySamcCq1ed6k9mn3UfMP7F+1T3nYqn2J'. - 'lZdoDEjpbq0KG8EBFBFBEJye6Zmenkv32Ydu5GYiUMmeqq6uqT'. - '6Xz3zP73aOcIKmAQkIFyD3N/jrBPwlKjLQEglVlJKyUjR3u7cc'. - 'WLoP3/4dvv03LNrQ8I6x1rFbDML9kOmHvh7IRHU9JKmUSG8vpF'. - 'IoXX/TV0AiEM5A5jT0noFMFMJHXUt/d5f9TUAbhtQ3cPFruDog'. - '8klHMnmO0dGYe/myOJGINEwTz3F2higFXgy8PpAkOC+h8hoaCt'. - '4ppHFcQAWSgOQlyI/p+lUjmRxWAwNJd3xca/f34yoFi4tgmjtD'. - 'NIFkJ4xcgBCgVqEBFJ9DqcZea/gNAAVEg7AOGYnHe9XoaJd3+X'. - 'LISSSwnz6lsbKCZ9sHh4UVdBkwdA6cPwNnIfJPmC3Ctgft3wwQ'. - 'QPkvTZJJnbExzfvsM2nMzVG7e5fG48d4lnXwTwEYCjJxuHQBog'. - 'BHUfKkgAIIhiGk06hTp/Dm5qS1uYlXLvtWd4gPgIiCrAEcVckT'. - 'Ab5p7TaYJrK1hQaEenrwSiVfQdc91P0kSp7Ii89D5ksY/kAkLy'. - 'IZXFdXkQjS1YUSEbdcRu168V6+HTUNIKJDRwdE+sBIQmP9Ld59'. - 'bEBA3of4F/D+uXb7rGaaCSmXI3pPj64PDaHCYfEqFVSjgWo2D2'. - '73XlJNQTgCyQykIuBWoNKEeh1aLXBPBCggGdBOgxZVSjoajVhH'. - 'o5HWlIpq4bCQSgm9vXhK4ZZKh5SUYygp4J1EQVUD9xlU18BJQD'. - 'bUbJ5T5XJStyxN9fSI099P3baxV1dRloW2h2ivx/yakg2ot6F1'. - 'EkCa4G1D+zVEq5ArKTWM42Q6HUczQV7U66w9e0ZpdRXlOIQ5vF'. - 'VHUXILKify4jiEzkOqC3peQMoBQymFlMt4Dx6wUSxSsm2UZXEK'. - 'P30QvOUt8/2Sd78CdWwFDTA+gsw3cOlPcPUD+CQB52oQ21RKXM'. - 'eRhGXhOg7VoKrx8KuS4ygZhVg3ZI8FGIfwR9BVgAtfwxdXdP3L'. - '86nUR91dXelNXTeWWy10paQHX602YAP1ADASAL7LJvFtMpOCc0'. - 'cG3FHuGlz6Gr4YEpnoTCbzsdHRbOzy5RCRiLRMk5rjyOtAimwA'. - 'U4U3SurBN/0wnAASBCVDIKpB4kiAB5Ub0/UvO9LpPAMDGfn005'. - 'AxPCzxep3Q6iqPLUseBoufCZRsAE6g5g5kKIDfKUj3wnpAG8QB'. - '/Z1OIqANQuI65AtwNScyYXR2XlAXL2YZHzcklRKWl5GVFXFtGx'. - 'MoAiV/EQaAGH6BUQNWgQpwFngv+Ca8KUAQEBcwgTJHyMV7679R'. - 'XS8YqdSI6u/PMD5ukMtJY3GR2uQkr5aXeWVZOEALmA8WsIAxfL'. - 'd0goVLAdCOd+/YpgqeVtBv4yiA++q/RKKXixe7GB8PSyoljcVF'. - 'yg8fyubyMpulEk2lyAIfAAvAC+B+oOQFoAt/+0rAejB/EzjNri'. - 'vvqNnCd64jxcE39V8spnP+vMbAgDSePKE2NcXm06dslMuUlcID'. - 'TuFvqwXMBU8N39bGgRR+ki0Dz4L5DSAe9NGD7zq+6kcN1L6H2b'. - 'ao5WWaQHllRTafPmWrVMJUimoAQrBYJFjQwre7B6A8YAi8LCgD'. - '5DVo6/hbb/iHK1KggvFeD3hHziQKEMuiNTNDbXGRTdtmw7Iwla'. - 'KGH0oqwbscLOoG46rAY6AOzRhY74PT6QuUKEN4PegXxd/yEDTT'. - 'YMWOk+oEaLkuFdNk0zTZwjfkavDUArXWgGXgFb4dEShXhfYqlI'. - 'ow3w9rg3B6ED60IOOA5oEYQBrcpG+mj9bg0VG8GMJhVDZLyzAo'. - 'VSq8rFYxXXefcjVgG9+uisDrXUCApoKSBcUHMBmHhfcgNwhtD3'. - 'q9IG6Lr15b4OUTmPwBJt8JqGuapp05o0mhoHnptLQfPsR+8IBK'. - 'uYyNH3yr+B77LHheA3tK1Ta+IrMeTL2C6Xl48TOsNWDDgAz7s5'. - '/r+krP/eddCsbj8fDQ4GBm9MqVvvRXX2VULBayRGRzaYn1SoWa'. - 'UjgB4PIB5QK4ZgBXBKaAHxQsrED1H7CRgCUPwgHZDqACmhWwXv'. - '2aDRqGYeRyufS169cvThQKV88PDuYbW1vJ5VRK+5euqxWlPMdX'. - 'SRqgreHbZGN3ijfKBXBTAeh2Fdwi2MofshP/dvKwCmKhp4m83Y'. - 'vj8Xg4l8tlCoXC0MTExMTFkZE/1m37wvLGRvKRacoD1209E7Fc'. - 'pZwYREOQqEJ4z3HskHLsz4AoXykPIBSN0t3dTTQafROoHdumXC'. - '4fjoMiog0ODiauX7+eLxQKV3O53ETdti88nJnJ3rl505ifmWm3'. - 'arWSodR8GNbycDoNHy5C5jFold1k8d+DyvELNwg93d18/vnn9P'. - 'X1oes6nufx/Plz7t+/fxhQKSWJRCI5NjaWHxkZKdj1+sjSwkJm'. - '+uZN/dZ337VqCwullGUVdZjsgIUC5LqhrUPvCugWuApeApPAzY'. - 'PKHWyaphGNRunt7WVwcBARwfM8Ojo6sCzrMKBhGLphGFEF2Wq1'. - '2jc7M5OZ/vHH0MPbt93awkJJmeZsC6ZaMK3DCwvWdNioQUb5B6'. - 'AdBR+9SzkAz/NwHIeXL18iIui6TjgcJplMMjY2th8wHo+Hh4aG'. - 'MsPDw6fddru7+Phxx51bt/RbN260qwsLpZhlFZsw9QJ+2Pbrga'. - 'oJG2FY2oKwuTtVEz9uV34NbqdtbW0xPT1NNBoF4MyZM1y5coWu'. - 'rq5dQBHRcrlc4tq1a/l8Pj9RMs38ndu3Ez//9JNXLRZNyuXZJk'. - 'xVYKoExQpsK/+IaAuYb7no8zjC/R+A4zisrq7u+53NZjl16tQ+'. - 'QIlEIslsNpuPRCJXZ2dnh2/duNFRW1oy07a96MKd575yxRqU1B'. - '5vPMpF5HHa1tYW9+7do7Ozc/eQpZTSQ6FQt1Lq8pMnT/5w7969'. - 'nuLcXE1rNufO9fRMhlKpOyvt9qPtVmvb25fFfvvWbrepVCqHwo'. - 'xaX19vff/996ZhGC8qlkW9Wt1Onz073fXxxz+6MB+9e9dUjuO+'. - '7ebq9wLdB9hoNCrr6+s/4wf3FCJW3fPmTZhXsNWCprjuW66Dfr'. - '928KAfBhJAEgiJSLuzs7OSTqctoFkqlZRt26j/I+L/AGjPTN4d'. - 'Nqn4AAAAAElFTkSuQmCC' ; - - //========================================================== - // File: ppl_orange.png - //========================================================== - $this->imgdata_large[1][0]= 2753 ; - $this->imgdata_large[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMLFQ0VCkHCzQAACk5JREFUeJytmGtzG0d2hp8zNw'. - 'AEcRdJ6EJK9FL0CqZUm9jWbkwq3vhDstl8dmLvz8rP2H8Q75ZT'. - 'pkRfpLgqsS6WIFEKGYkiSBCDO+banQ8DUpRWEkklXQUUqlCDfv'. - 'rp857pgfAOQ4AMOJdg4R/hX96Hf06bvDc5iT07i8yeg8ksiIAI'. - '4TBi/ds9/vivD/njapNHvRBfHXMu410AM+BUoVSF05NQsi1sO4'. - '8402AXwLQTuP31OAZO2aG0MEn14iSlnI1z3LnMk8IZYJyBwjIs'. - '/TWsVIWPJkvMFS4zMfMhUp5BsoCpAAEBLYKaMFGn00jBxnvu02'. - '35+JHmSJEnBpQEcPo38MmCxd/nS9Ry71Ga/g1W9a8gn0GsHkgA'. - '6DGjxkqb5CoO+YxF3A3p+jGjQUzoK+L/V0ADzFMwtSR8eLbAr8'. - 'uXOTf9NzhTc0geSLUQcYHgYEH786RMg0zWJHV2Aitv4x/HpHVS'. - 'QA2YBqTTGIUq5qkPMWaWkVwPnPtAA/BevmZcjxaaUtHh8pJJGu'. - 'DpCB9FvT7A7YT7S3p5vFMNzmWo/O0MSx/Ms3TqI8r59zFTfUQe'. - 'I7SBODE3tnfoIxYnNHligwik0zAzDdVpyKbA8sff5YAeMEwgkV'. - 'cufQeTJzZoCsaFLKXPTnNpoUTNsSgJmNoGsuNQjIDwYD2HlnZy'. - 'k++yxTKXZfKTU8zOpjhneeQYkorSmGERtIlICBKRbLX+y98YN3'. - 'ADcNIm+bJD4U3pPnmbEaRgYVRTGBkDSSsmxKfY7ZLuDJA4hdjl'. - 'JEgyBB2SJOvQ9RzTpNKoEwNq0CNFvOXR3/HxMgYVPObaz8kPmh'. - 'hkEWMatAfRONGGvLizyOE9P8KkpwhPDAgQKJQbELUD0oOIhbbH'. - 'JeVTmowxjAgZutB5AoOngA+2DdYrcTyOyYZP9+QpBvI29vwEhb'. - 'It042BVQgDy9KTMfkwQG1A9ACCLlgBBGUwxxoc52WDh2ATyEPp'. - '1hoaPvrEBh0Dq5an9OUsl/9hylk5b5c+mowLc4E2Jtw4Eoljyf'. - 'ogA/AGEAagNRjGyUxOmEycyVA5EWDBxrmUp3ytLIv/NJP69Goh'. - '+9mFydIvS5PZYkvH1oY/RFtKymlwBFQAgQd+kAA6qSQ8pvn2mp'. - 'SkJkuVFHPHBnQMrEt5Sl+e4/Lvp51PF1PF5Xy6WMvOWZXMom8z'. - 'OZTQ8+j5sbQiMEwopsCIwRtBGIJSCdzbTGo9NimkDcgdC7Bg49'. - 'TG5n4/nfr0Si77WdYp1YzyZEkWPdteaEnB7pPqBTxuIf/VgciE'. - 'SgasCPwh+GNIkaNNag1RiPge5pEhMQVjfoLcF+eoXSvbKxedwn'. - 'LKzC3KWbOi5/sW5a44/SHFUSgVA7SCzRG0AvA9mPOgFIETgu4n'. - 'Ww0wNQWFAqRSL6D2ZQYBdDrQ7R7jXiwgRcvIL02makuTmWtpM/'. - '+BlLMl5vuWzLVEuwH6oYnR1KS8kJINGXMM2YdfRlALoQoQQKeb'. - 'bDVwoMdxQMaLCwLo96HZTF5HbrEhmOftianfZisfzueKv7ZmrX'. - 'MsjhxKXZGBjzyeEHmSE3oWiggtyVGmE8DTIXTC5NxgAxOAGUM8'. - 'fun9mnSSLQ/CxNzOTgJ3LIMgoGwkKBiiMyaVviHVkdCO4FEKNv'. - 'LQzWBYHfITPa4UBVM0LR/WB7ARJsdDDTjA6deYFIFUOimJ3d0E'. - 'sNdLavYYgBpthqKcjiiJRO8K6CK0CsJTjfQAGaJtD9vQFAxNNQ'. - '1FB0yBAfA8gdMAIagLoCVAen0M00zMOTYShNDtoHs9CAIUoI4E'. - '1IBihCdNhsMhsj6NuV7BCC2IBpBqQaaFOENCCeiEsO1BO4RQgy'. - 'I5Hm4k4oIU9MrgZSAdBeTabZz+ODxKQRRBFBJo6IUc51anYRQo'. - 'dto+24FNxYCiaWKkQsj00KkO4gxRRkAngJ868M0u3OkkM+hxQA'. - 'cQ7YD7GO5XYSsPZybh/TCkFIYY+kWniTW4Q7jXgHvHMhiRpmuW'. - 'ca08GZkkZ/nY6TZMNhCnf2CuPoDVJvxpB+q9BHA8Ag1uH+oP4c'. - 'YEPCzDwmzSLquShHW/E0YRbG/BjZtw40hAy7aNzJlzRn75E6N0'. - 'qiwTzafI7kOU3gWrhzZC2iHcbsPqLlxvJnCt4KC1RYAL3I5hzY'. - 'Xv/huePYCtITQMKEnyB4KQvMURuJvw889HGSwUCs7CwkLpo6tX'. - 'Ty/+7nel6VLGDn/8N9m+eZuo1UP8iNhLau6b3RfmOsHBGTUYw9'. - 'WBNeDrGB4+h/4qNLKwTnLbHj9CJw/6GoIh9Jpvq0HHcayFhYXi'. - 'l3/4w9LK8vLKexfma3G/mb/3n1njTivS7tNQaaU1grQDjJ868D'. - 'Axx6vmxnBrY9C9IcSbSXbavNjb/S3eN6/0m1JcKBScixcvllZW'. - 'Vi6uLC8v12q1v/M8b/HxVjP//YYr32yE4dYWvShO0ogi14xwxq'. - 'F4rbnxZ3cMjtpvEEeMvwA0TdOYn5/PffHFF7Vr166tvPeLXyx7'. - 'nrd4+/btyg/frFo//Xgncnd67qCn78earQqcmYD3fSi1wPCTSV'. - '3gzqvm9uFOMl5nUAqFQn5paal26dKla57vf7D+6FHph9VV88af'. - 'vgq79bo70e3VT2l9A3hYg4UiRALVHTCHSZvYBm4A//6quf8zoG'. - '3bpuM4acMwKr1+//SDe/dK31+/bv90/Xrcq9fduNW6rbVeC+E7'. - 'gWdD2DKg4UEpBmPcm10RuScida31ntb62HAigoigDw6Gh0axWH'. - 'QWFhZKi4uLZ+I4PrVer2e+u37dXPvqq6hbr7tOp1NXWq89h6/b'. - '8FBB34WGBesdcPrj38lkMkGlUuml0+mu53nR3t4eo9HoSLhMJk'. - 'OlUiGdTuN5Hq7rvgA0TdO4cOFC7vPPP6/VarXldqdTu7m2lrv7'. - '7beq++BBO263b/tKrfWSXlbvwJ6CuAtDgTYiaBFMw6BSqfDxxx'. - '+rarWqGo0GN2/eZGtrC6XenAkRoVKpcPXqVWZmZmg0Gty6desF'. - 'oIhIOp3Ol8vlmmVZK3fv3Lm09uc/Zwbr653ccPgoNIzvnmn99Z'. - '7W9QG46lAaM5mM2l95GIYUi0VOnz7N7OwsWmsymQzyuse5Q8Mw'. - 'DNLpNDMzM5w/f/7A6AGgUkoajYa9urpayOXzUz/fvZutr68Pim'. - 'F4/2y1+n2o9Q/ru7uPesPhXnyo4A+vfHp6mmazybNnz9jZ2UFr'. - 'TbPZJAhe+8/aS0Mphed5NBoNABqNBqPR6MWBVWstvu/nnj9/Pv'. - 'vo0aPq5uZmPBgM/qcwPf39xV/9ajU1M3Nvq9PZaw8GoT50PjdN'. - 'k6mpKa5cucL58+eJ45j19XWePHnCzs4OnudhmiaWZRGGIVH05r'. - 'yEYYjrumxubrKxsfFyDQJ6NBp1Pc+7C4jWumBaVm+kVL2l1H2l'. - '1G6otS+H6V6z8u3tbVzXpdFooJRicXGRqakptre3uXXr1ltrcT'. - 'Qa8ezZszemWAE9rfUdYBOwtVLRbrPZ+48ff+wDvuu6Sr3MB4Dr'. - 'uty6desgfa1WC3iRyrNnz4pSSmezWUzTfGtYtNYcdvC/9sMlgP'. - 'n5N4cAAAAASUVORK5CYII=' ; - - //========================================================== - // File: ppl_pink.png - //========================================================== - $this->imgdata_large[2][0]= 2779 ; - $this->imgdata_large[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMLFQolY9lkpgAACmhJREFUeJy9mOtzFNl5h5+3b9'. - 'Mz0kzPBWmEVtIiWYhIiC0HCDhB8lb8ISk7nzdZ5+/zJ/8BTmpT'. - '660CZLwG1pVFgBkgGIHECEaa+/T9nHzQCCQuRpCNz6mp6g893U'. - '8/c37ve3qEjxiC4OA4n/Lp/EUu/tsMM/+aEWduVBx7WhdkShcY'. - 'xUH2zo0Dwod/5N6vf8V//PoGdx8M8EOFPtK9jI8BdHCcMuVSmf'. - 'LxHLmSZdm2U8xIbmKETDGDZZnIy4dBbCynyGhphurEDBOlHFnn'. - 'qPcyPxTOwDCOccw7w5nlBRZWylI+ny/mZ6rL1dzUZ5/IWGZU3D'. - 'ZIOMQDDaJcHDVGWUbJBi9odVr0QoVSPzigIEaZ8vgSS/8wZU3/'. - 'k1fylipz5dLM2WlrZqHKaGCKbEbontq3KAKWQyZfZKTgYqc9Bp'. - '2I2PcJ4ogk/UEBQcwipbFZmT13vDBx8fhnE1Ofnp9yJopFyT3X'. - 'yANfks0QHSQMDaL37pOxMLIu2UyVkjVKLjyKSeuD8dAYCFkso1'. - 'gYMaeWJ40T56cl8yAi/O4FSa2P6kYczIDsgVpAqcDImZPMuAB1'. - 'dkLQtcc8a/bwox8IUHAxZVxGZMouSLVYwKuMkD5IxN+JSdsRJB'. - 'pexuTVgYYM6EoGmxkmg3/hEhNUMr/hd7dqbOzExMn/GRDAxWZc'. - 'j3I8HiXfMjF2FQowKw7pjoN6E/Llw/GBJj8qxVOMlX4ipxc/lY'. - 'kl2zBLkmrTcEzMkoNoRLVidLi/9g+Z3I+1xRHX5EcAihxnbPRv'. - 'OTU9kZSmpKPy9FTGrLimPZ1H+UiyGaF67w6n7E1DwMngFDxGvc'. - 'w70v0xZUby5IxjlIyMssUJrJwVWkXBdbXvSvwEibcSdKCAFI16'. - '4/sc0SRo9cGAGq1DwvQFzV6DVuBiV4zYnlEts6A2TSPcSiXoxo'. - 'QqJCEEFMbQ2b69o5qMiOOPqIMQkagu/aSL7waE8101WFShLjk9'. - 'yxgEvjRUiyYd+gwAjY2J9VpXfZ/JEXLhDp3OR6U4T97+hEnPwx'. - 'tv4HsRjy2tTQSFzQgDUnwSLBQRI+x1ZgcH87Vcv4SF19Kt0ezS'. - '1h9s0Ma25pgr/YJfnLnEysok0+ezjM6EBLldGqKIJYuDRhOQEJ'. - 'Oih8X9Q0xmcXNjlCofBJgn78wxVz7L2YWf8tPPz1hnfjbjzfxN'. - 'qVwutq2etZXUQSXikcXGIgUiUkJSDIQMJgYGJsaB3c7b1qQ4GZ'. - 'xSkdGZIwMeNLfK6uezMnvJK3pLxeVixfvMsyVjSNSO6IV9adPG'. - 'AArkEEz8oUkFmBjYGO80qfd6pCWIayD59wIKcsjcKqufn7JO/S'. - 'xfyi+5c24pey5rZ09mJRNkiDdT/tzbkBr3SYkpMYpgEaIJSYhI'. - 'kSOY1GhilAQk5ntDIojxCZ/kf87Pl85xbuWEnLiUy+cW3NNuJX'. - 'MmY5meKf6mT7wZS+THdOjxlG06tIlIOMZxchSxcFFEGAwAGGME'. - 'jwyZYSnWL3cXWiIUbUI6hO/vxXuFOV84ycmlBWthNeflTjuzTi'. - 'lzJmM5s46Ej0J63/ZoPmoy6PYxtYVNhmfs0mbAND1mmKVMBY1L'. - 'mxA1LN7WgXQbCApNhKJHRIM+DQbv7yQGhjnJ5NgFuXBuxpu5mD'. - 'udm3LPuY7pmZLUE6L1SIJaIPFuDAqyw9lnwDYv6NFHkWJh4ZDB'. - 'wCBFD3uMxsTAwcBAiElpE/KcPg36dIiOvpsRxDCyhmlP2YY9ZU'. - 'v8NMb/1id+FGO0DTztkSXLOONUqeITsMkW2zwnJEIDFhYGx+A1'. - 'kwK4mASkvKDPc3p0iYhRRwYUhZLUTyV6Eu0t4s1Y4kcx6W6KaM'. - 'EZThcXH59RRhGEgIAddnBwNEBKqqpUtWBIF22YDIhJsbEkJqFN'. - 'qLtERHs7GnUkwISEQAf0uj30bY39PzbiC6qrDu2cExJ69Nhhhz'. - '59UlIUipCQOnVi4sjG7ubJBy6um0C+he/0iDHQKIQERYyKFLqr'. - 'SI/W6kJCnvOcrWSLSquC1/Jw9Ks3R0FQKHr0uMc9bnCDGjX69A'. - 'H0XlcJkibN5jOe/alCZStHbjJL9lSMLkXExvCXRiDV6GZEeGeX'. - '3TvvBVQoEjfBL/v0rT75Th7VU5C8gktI6NLlMY+5yU3WWGODDf'. - 'r098tHpNFNH7/2lKdXXdz7efLzVaqJIBOCmK8AJUlI6g0aV+9y'. - '9+p7AR3bMQpTBWPy7yeN6fy0jNwewfpvC9Xe+3kFoUuXe9zj5n'. - 'BusEGHjh6GIAGawC2FWuvSvbbF1maFylZAsC1ISZADBiVNSJrP'. - 'eX73MY//skHP85z5+fnSxQsXj//4n39cmnPn7LbZlsajBmEnBL'. - '1nuEGDG9x4aa5Ldz+h0RCuBqwBv1Wo+7vs9r7n++0MmYeAM+zB'. - '+61EK1QUEnbbtN+9Bh3Hsebn54u//PdfLq9eWl2ZnZ1dSnaSwu'. - 'Pin40b9g3doKE0WoNIl65xj3v75njd3BBubQi6ExKmDWkMRKSl'. - 'tSbVKQcMao1Go5Ugb0+x53nOyZMnSysrKydXLq1cWlxa/McgCB'. - 'Yev3hU+GPrD3I5/q94k3pXYQY58q6B5Bs0HB//neaGx00gyWaz'. - 'VCoV7bquCoKAnZ0dfN/f03egLGj0m3XQNE1jdnY2/+WXXy6trq'. - '6uzP3oR5eCIFi4detW5feXL1vr679Let37zVB3/mQytjXJwmSB'. - 'wikHp9ShY0RESqObwPrr5oBERKhUKly4cIFqtUq9XufmzZtsbW'. - '2hXvuDwTTNtxZq8TyvsLy8vLS4uLgahOHphw8elL69fNlc++qr'. - 'uFOrNXPddm1cczVL5f5P+Lv5MuOJgTGxwYbZpZsCdeAq8M1Bcw'. - 'CGYeC6LtVqlRMnTjAyMkKn0yGXyx0N0LZt03Ec1zCMSrfXO37v'. - 'zp3S769csb+/ciXt1mrNdHf3ltZ6Lca8ZpJsduhtCdb2gEFJoQ'. - 'xADYHuHDS3f32lFEEQUK/XGRkZoVAocP78eZaXl9FaI/Jq25Uk'. - 'yWHAYrHozM/PlxYWFibTND32sFbLXrtyxVz76qukXas1M61WTW'. - 'm99gx+20TdN9jqtfjP7QzOwwYNp037Zd0DukDnIByA1pqdnR2+'. - '++472u02Z8+eZWJiAsMwDsEBRNGBzYJpmsaJEyfyX3zxxdLS0t'. - 'KlVqu1dP3q1cLta9ekU6u1dat1J9b6Sk9kraV1rYXegW7apDYw'. - 'kFY6fPc4MNTw88bwfZ/NzU2UUnieRxAEiAiGcXiXfcigiIjruo'. - 'VyubxkWdbK7fX1xWvffFMInjzBM82uMT5+p++6V1UUrSe7u03t'. - '+8lezlKt3gHyl0aSJDQaDa5fv876+vo+w6FzDq1BpZRsb2/bly'. - '9f9vL5/Njdu3fzG0+eMJHNxsfn532vXN5NPG/7abPZal6/Hvfe'. - 'kroPHfsm98f7AHW9Xo+//vrrlmVZm71+37QNw3JnZ9PK4uJGpV'. - 'pt4Dh+vLGhsrmcfv1iHzu01m89HjIdCon2fb8TBMHtvYeRUn50'. - '1Oj4vqp3Ok1f5LYSadfr9dQfDN642P/XeF2DA+SBAuA4jkOhUK'. - 'BQKESO43S11p3BYBDt7u4y+CtB/i/q7jp1GMiw2AAAAABJRU5E'. - 'rkJggg==' ; - - //========================================================== - // File: ppl_blue.png - //========================================================== - $this->imgdata_large[3][0]= 2284 ; - $this->imgdata_large[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMLFRAiTZAL3gAACHlJREFUeJy9mGtv29YZgJ9zKF'. - 'F3y/Q9jh05tuQkarKgbYasde0UBdZgwNou/Vqga/sD9mP2B4a1'. - 'BbZ9atFPxb5sqOtmXbI19bqsluPYiR3HN90vFEWRZx/IJI5zqa'. - 'x0OwBBSgR5Hj7v+55zSEFXTUgIJyA9C6/9RsjMjAyFIxxJCDc7'. - 'iBqKgyZACGg3G2x9+xXf/fG33P3mC9qNKsp1O+1JdkEnQTdgIO'. - 'ttCSMUi8gj072MnugllAyB9G8rBGi6RsToJTF6iuRoFi1kHKZf'. - '7fB8Iggj0/Dy23D2dakNTR3JDsXPvzstxmZGRMER1EwHhQAEgE'. - 'CLhIkPD6InY9S3djGLJVBtQP1Qb4HDAyoJYQOOZkPx49nhTH9i'. - '7MUBGT7egxkJgd70wZS/CUkoZtA/fRoE1DZ2ACiv52ibReCp4e'. - '7CIEHomxDiuVdGTqUnf/ZeOjR8fpiVXZul5ZrY3bWwbdcLr/dA'. - 'AAIpAwQjUWIjQ+g9HZvswiCgBVF9/SI6OSLGzo0i+oLi6+Utbq'. - '+bKEftgwOE/0Ohocf66M+cBjo22U2RQLIHMhmYnvaOpR9S8bSU'. - 'UqCURGpRkuMZMm9cIvPGJZLj0yBjT2LprkiSkykx9cuXIhOnUs'. - 'm+QNC2XdG02ggBTcvFabsPWwTPpBAChSCgh4kYBpoeplWp47Qs'. - '7EYDt21xINzd5GCAxLExRl89Z+nHjpbKMmjbmkgfDzI0JEW53K'. - 'Jaa6NcAOEX8v52uJzsBlAS6u0hcnTIccPRqhWPCUcLD+s1EaUp'. - 'HCEhEMCyHNpt9SjgIU12A6iw6xb123vYhaaKjB9tlgMD5X+uBp'. - 'zdkpg6azA8EaNQtKlVba+Xez4eCntnJrsDdFsW5nYFpxlFN846'. - 'DXe8utkM4mhi+EgQmjYbS2WqexZKk6BpjwJ2YlK5VjeA3pNDiH'. - 'YjRWPzPE7tmBo8EWwGhkXx+z3uXL7D3rU97LIF8RBEAl6lK/Uo'. - '6JNM1rZ2aTcr3eUgIQOGTgbdwXMGyRejenLYTvQGbAdRuetSud'. - 'OivVuFZgtCEgICghICnZoMhmlVTPR49LCAEkQUhk/B7KXe0MWf'. - 'nxj8xVR/cDheK14WZmtVMJSBnlGoN6FmQq0FLfdwJgORKPHRo/'. - 'Snzx4G0F/FjJ4KiOdmjPCrrx8bffnMybMv9MQGNG3rzlVqtR1B'. - 'sh/CYXCD4Aag1oCW7ZnUOjSp6WFi/QNEB8Y7BfTNjZyCmUvJ0I'. - 'XXT47MTp98Ybon9VZCk8cVazfqlNargsY34G7ByAlIjkHd9CCr'. - 'LbBdiHViUgiECuDKYCdz8b2cywREdiYZOj8zNnLuzOTzx6ODp+'. - 'OaGaqwVzBFqz0Idhz2loE7YEwBLaAJLQcKbW8qjAcBF5Jh0AMP'. - 'IOHe6kxgtb3UMO2OxkF//ffK28nQqxfvm3szrtnDVa799Qb/+v'. - 'NtsbNSpm3tAv8B+w7Ub0FhAyoBcMPec9oK6raXk48ziQBXQcmC'. - 'pT3YqHa0mpEBkTR6wz/Jjo2cy04+fzwxdDquNfQKO7sFUbpu0c'. - 'wp3JoAYsA42Bbkl4GCryUNDEM7Avm6Z/CgSYBWG8pNuFuDu1Wo'. - 'tjoxKIJGeHIiM/jmK9NnX5ycuJQMtUcqXPvLDTa+qIie4hAJ1U'. - 'vdrmO2HaDfB931twJgAn1A4lGT96obPHPLBbhVgUoTHHWo9aAA'. - 'JVAKpyKEmQNzWRENAsL18ycKjAFN/9gCNvzLB/390MMmE7pnDi'. - 'Bvwt0K5Jv3O+0oB22nJ1Vvjb/UMhOpcKknqN1OiMB2DNHU2G5s'. - 'sVndpGJVcZXjX1IAlvw9PmhRQcOFPhsSDkiBrQR1G7brgs0a7D'. - 'ag3FK4rguqBXarI4Nt1SJv5gls7TEWtJDRBO2GwnIs8maevFnA'. - 'Gx6awLZvzeTBu4kFbLigijC47pscpx0xyDfkvtUEnlarCDtrUC'. - 't2HGIhvPHVdVwqjTIrxRU2a5uUrYoP0QZ2gMvACl7+3V/LuKDq'. - 'sJuDy597516+CEezIHXv7vcgXQu2l+Bvn8He9Y4AE4kgk5P9DE'. - 'R6aFdq5Et5Nit3yTf3m9sBcsAN3+D98c0Fit5JawE25r1zg1Fo'. - '5B8GFD7g+nVYnu8EUEop9XTa0N/9dUbqcphP/rDJzbUClVbpgR'. - 'y2fXM3fND95qj75J8AC6BWPINfVSBieK+x+6cS5UCzCLu3oFV9'. - 'GqCMx2NGOp2Znpv7aXZudsool3T5J/179sxVlHJ4kGPrP2COBX'. - '/7DmiApWCjxIMXpYNznYuXM+6TAKWUMppOZzLvv//ery5cuDCT'. - 'SqVS336bCwr1JfAPB9r+2KAFwJS+OcETzZHz/7v3etl6ipz77X'. - 'GAMh6PG+l0OjM3NzczOzs3k0pNnFlbW43+e/GKtMqrblSsF03V'. - 'WHcJA0PjIAzvg9JTze2H67g9DjAwOTmZ+uCDD96anZ2dnZiYmF'. - '5dW41++Lvfa1fnr7qllVK9103mXNTnJgPA+YugsvB3HTaEl+Qs'. - 'AZ/yeHPPDCiTyaRx5syZbGoilV1dW00szC9oV+avusuLy0Xd0X'. - 'MgFkDM+zkYBZEHV8f7wwKu84zmngQoNU0LaZoWUa4K31y5qX/8'. - '4cfyyvwVN5/L10NOKNeg8UmDxoKF5Vfj1xXAgD0JrgAcvBDfel'. - 'a4g4AykUgY6XR6emJiIru2ttZXq9S0K19eUcuLy8WQE8o5OAsN'. - 'Ggsmpl+NpoL1g9X4UBU+C9xDgEKIwNTUVOqdd955M9mbnJ3/cj'. - '6Vu5aTheXCQXNdVeMzAwJSCGEA2XKpnF1cXIzlFnOVhJPIKdR+'. - 'c88ctq4AlVKsrKzw0UcfKcC5uXqzXnNqSzb2pwLxOHP/l7Z/BN'. - 'eB01LKt4HTrusKvGr8jB+hGn8MQAkYQMrfw4Nq/MFPtf+rdvDb'. - 'k8QL+/5Z4Uepxm7bfwHuTAVUWpWaqAAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: ppl_green.png - //========================================================== - $this->imgdata_large[4][0]= 2854 ; - $this->imgdata_large[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMLFQ4hANhluwAACrNJREFUeJytmF1zE1eagJ+3u9'. - 'XdkvUty2AbmLEtEzDBgZ0UpDBOalNTUzU3czl7tct/2n+wt3M/'. - 'NVM12SSTQQSyW2TA+QAJQogtYYFtyfrqL3WfvWj5g8AEjzfvhS'. - 'SXjk8//Zz3Pf3qCMcJAWxMKlT4kH+jwu/FknnJSUItKFHzCrKA'. - 'BggBQx5ziz/wn/yBz3hED4/oaJfSjgVoYjJJgTLTZCjohp7IGT'. - 'k5aZ4kb+bRTR30Q7djj8f/kpPMUSCFedRL6W8e8qMQNE6S4xpv'. - 'c5HrTPFubiJ3ZnlyOXV59rJYU5Z00h1c3d0brxAiUkScRijisk'. - '6XLTyiN3s8HuAJpniXa/q8/pt8Or+0kF8oXJm5YiydWcIpOrJu'. - 'rjOQwd54AQwsMpTJYhPSoYuLQ58An/DnBQSdImXO8avsTPbqpc'. - 'lLp67OXDVzMznZLGxSs2qyIRu4at8gKHQEC50kE1icxqCAdxST'. - 'xjEA44tqaJlERl8uLWvvnX5PHuQfcCdxh5qq0aX76vj4WgWyXO'. - 'QiNgBP8IAaddr08X8+wHFmJSQhBbPAZGoSZSt5wQs6qoNC7UEd'. - '4AEoLIQSCaCCy78Dv8Tiv1hjjW1CRj8XIAgEKqDtt9keboMJZa'. - 'vMjuzQVd3Xr9prTJo+GF/jKZea95R25Lxs8jg5qFGiwDnOS0mW'. - 'NE0rjNRIt3WbklUCA9mV3Zdz8OBT/JfCQLB0SKYVVjGFYSfx/E'. - '26ow4e6uDujlPFQpE0FU6P8qNTHdXJdEdda0qf0itWBVM3pa/3'. - 'ccUlIECJet0cAJoeYk5EZCeS5IwEoerSxccJBwRqFFf38QCTaO'. - 'TRVFKJm3NTbtLNSyh2IkhIXsvLCesEGNCWdmwyruSD/z9kUlRc'. - '3bqNlSxhJNJ43p5JITrOEis8Qtr0cXEpU/JT/pmO18n2vb42pU'. - '3JnDnHMBqyPlpnoAaxhr2llv1ZUBqEGlqYwDQMsskMOcMgVL3Y'. - 'ZOQTHAcQQiIGjHCwCaiovjrv4hbcpKuJJjIcDHm685RGr4GLCx'. - 'YHkAcrLoAoDSLBiAQrMkjqybHJCbxgh+7xAC1MpsgzwRwD3qHL'. - 'WyTIBdlAa6u2rHfXaew06PV78ZZjAwleNnkolECoH5i090wOcY'. - '+TgwYzFHiPi1zkOkXexeAMASnVU+LiyiA1wFUuaqggACLizeWw'. - 'ycMzyssmVYKkbpGyC5T+OUALk2mKLHKWf+ED/az+YW42d66YL+'. - 'aNrmEEzQCFEnKw368EgEvcN1m80eTIQIt0TFOjMJHkzNEBBYPp'. - 'sblf8QHzrORO5JaWZ5ZLl6cuJyyxpNPv4PZdoT+GyIxBfI5uUg'. - 'eJMCwP2/bIHO1JEudcgUUWOceKNq99mCvnzs5PzRcuTV4y5mRO'. - 'SMIjo47z5S7a94oQCNKgJsZwO7D/IDNg3/LLhRNXt4JohBb4aG'. - '82GLdXcf93mQ+Y43r2RHZp+cRy6cqJK4l8MS+tdItaqiYtc0Mm'. - 'QpfJARh98HYh9IiXVcaAo58wGb+LBAjbSPgCOcoSa0wzxXtc08'. - '/pv8mfyL+9MLVQvDJ1JVHJV6SZbFI1qtTsB+KlehRtRTGE8Afo'. - 'P4DRcAxiEudhAHjjzz+ubgX4oHowakHQOlqzICQwyVPITGVOXi'. - 'xfLF6aumzmczl5lHzMff2+fCdPaGttEkXoLQAO9B7C6EugPYby'. - 'gVPjGXc5eIbNAJPjGwiAbaAJUQv8wVG7GROkJFpyOqn/ovgLba'. - '44L0+sDaraXb6jzq7aBQWjBOyUoHcaopOgmaA3IRyNDZnA1HjO'. - 'HSBkr7eEFDAEngHrQCf+/s2A8cSiSkqcKUeeTjwFy2Jd78t3+L'. - 'TR4itIiBLwLQhzkJyB5Cx4HXDaENVQCBAQcRqFIHTRaBIvuYXg'. - 'AdsouuNxEL0ZUBHnSQp66R73zYfUtQ6OytKT8RckQAJQoLtgO5'. - 'BJgj0D/WfgdyHaAHx8THoUcbGx8ciwhUl3bDEiToURPooeI7pH'. - 'MziK9Yd9nU5a6GgKjOH41vsgI4hAcyC5AZkapF+AoYNrjjsuhx'. - 'FbtPmeB5ykyQQzTPAWAQWC8S9oAI0QRRuPb9jkmyMZNAOTklvC'. - 'GGYZaFkGmkVAh8h4DtKFMIBunG+pB5B5AIkGBDsQ+qBiL20caj'. - 'zhJknq5KlgMkLjJHJos4kYEbFJi5vc5eYbATVN02bNWe19+32t'. - 'aJWlFm3wbf8Rz5NbDFJdlOFBF/g7cBf0JkrbBb+F6j1DOduEkU'. - '8bWCOiSofPWadBnSZDWmgUkEMGhZCINut8S/0NBtPptFlZrBSu'. - 'vnt1+ndnflfIp9OJ/279Ubbbd+lP7KBKPoEBsgnqLph/BRzwdS'. - 'LnBUFvHcfdpRsGPAGqwMco6jynz+e0SPKYCHMfLX5VKHwcenR+'. - 'Igd1XTcqlUr+xn/cePv91fevzy8sLO2OtrOpWkqL7gXKSAVRdh'. - 'ZFEmEXoYkwBNqovoc/3GHH3aUR+jwC1oD/AWrANi4hGwyBzqEG'. - 'Vvb77Dgi0eT1VZzJZMxKpVJYXV1dXF1dXVm6sPSvruue3Xzcyj'. - '6/syvDzwj0lNazK6Fj5LFCRZouZpBABj6jXouu3+Np6HNvDHaf'. - 'g91t74msbMuOJicnSSaTKKUQEUQEpRSO69But1/dB0VEm5uby9'. - 'y4cWNpdXX1+sLCworrume//PuXpeqnVeOban0U1PW2kcx+O9L7'. - 'Te9sUB4lWFR9SqNtNGcHx+/RDD2+Am4D94CnQA8OjjlEhMnyJC'. - 'srK8zOzu7BiYioMAzZ2Njg9u3brwIqpSSXy2WXl5eXLly4sOo4'. - 'zoV6vV6oflrVP/7Tx8Hmw1Zb6ydqmpWp7ha8h4O3gjOhzVANmF'. - 'XPMNQWvdDnCXCXuHR+APqH4fbCtm2mp6eZn59H13WJuYXRaKSU'. - 'UiSTyVcBdV3XDcOwRaTU7/en19bWCn/79G+JL/76RbhZ22y7u+'. - '6ahl71nPDz/nO17m7wAxlabFOihy4+DvAcqAMbPzZ3OFzX5dmz'. - 'Z2iahoiosUUVhiGNRgPHcV4GzGQy5uLiYuH8+fMzo9FoslarJW'. - '9+elP75E+fBJu1zY7qqpqBUW3T/niohnVvy+1zm5aVtp+WE2XT'. - 'nrHFzbjh1tYLz3XdPjD4R3BKKba2tqhWq4dzUO3noBPn4H5PKy'. - 'LaO++8U7hx48byhQsXVne7u6tf3/v64t3P7mbq9+odt+OuaWi3'. - 'PLxbW2ytubjbQCgiMnt6VlaurWgz0zM0m02q1WrUaDSUUuqI56'. - 'ivDxE5MCgiYllWtlwuL5mmufLV/a/O/uXPf9Ff1F+80Lv6Yx29'. - '2qHzyZBh3cdvc7gaTZuZkzPh/Py8ACqVSv1/uPZDKXUAGEWRtF'. - 'qtxEcffZTL5XLF+2v39fqjeivshA/TpP83JLwzYFBzcA4370Cc'. - 'S81nTRBUs9lkOByi1GuOPI4Rh3+26JZlnSkWi781DOPXvV4v3+'. - '/2G0R8kSBxB/jew+tERK+c49m2TblcxrZtXNfl+fPneJ6HZVmU'. - 'y2VJJpNyaJ9TSinlOA5bW1u4rntkQA0oAG8D54gb9W3ianxM3A'. - 'e/cn73U3Hq1Cm5du2aPjs7a+ztcSIShmE4ajQa6tatWzQajZ+0'. - 'fbiKI+It4SvijVUj7kL2qvGfgkskEqTTaZmcnDROnTplJhIJTU'. - 'QiwPd9P/Q8T6XTaQzDIAiCfzjP/wFVfszuFqdHXgAAAABJRU5E'. - 'rkJggg==' ; - - - //========================================================== - // File: pp_red.png - //========================================================== - $this->imgdata_small[0][0]= 384 ; - $this->imgdata_small[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. - 'B3RJTUUH0wMJFhouFobZrQAAAQ1JREFUeJyV1dFtwyAQBuD/og'. - 'xQdYxa8gRY6hJ0jK6QdohMkTEuE5wUj5ERen05IoLvID7Jkn2G'. - 'j8MgTMyMXqRlUQBYq9ydmaL2h1cwqD7l30t+L1iwlbYFRegY7I'. - 'SHjkEifGg4ww3aBa/l4+9AhxWWr/dLhEunXUGHq6yGniw3QkOw'. - '3jJ7UBd82n/VVAlAtvsfp98lAj2sAJOhU4AeQ7DC1ubVBODWDJ'. - 'TtCsEWa6u5M1NeFs1NzgdtuhHGtj+9Q2IDppQUAL6Cyrlz0gDN'. - 'ohSMiJCt861672EiAhEhESG3woJ9V9OKTkwRKbdqz4cHmFLSFg'. - 's69+LvAZKdeZ/n89uLnd2g0S+gjd5g8zzjH5Y/eLLi+NPEAAAA'. - 'AElFTkSuQmCC' ; - - //========================================================== - // File: pp_orange.png - //========================================================== - $this->imgdata_small[1][0]= 403 ; - $this->imgdata_small[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. - 'B3RJTUUH0wMJFhwAnApz5AAAASBJREFUeJyN1dFthDAMBuDf7S'. - '3BCm2VCRKpS4QxbhikW6IewzcBqm6Fm6JyH7iEEByCn5AJH38g'. - 'BBIRHNUzBAWAGNfe/SrUGv92CtNt309BrfFdMGPjvt9CD8Fyml'. - 'ZZaDchRgA/59FDMD18pvNoNyHxMnUmgLmPHoJ+CqqfMaNAH22C'. - 'fgqKRwR+GRpxGjXBEiuXDBWQhTK3plxijyWWvtKVS5KNG1xM8I'. - 'OBr7geV1WupDqpmTAPKjCqLhxk/z0PImQmjKrAuI6vMXlhFroD'. - 'vfdqITXWqg2YMSJEAFcReoag6UXU2DzPG8w5t09YYsAyLWvHrL'. - 'HUy6D3XmvMAAhAay8kAJpBosX4vt0G4+4Jam6s6Rz1fgFG0ncA'. - 'f3XfOQcA+Acv5IUSdQw9hgAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: pp_pink.png - //========================================================== - $this->imgdata_small[2][0]= 419 ; - $this->imgdata_small[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. - 'B3RJTUUH0wMJFhsQzvz1RwAAATBJREFUeJyd1MFthDAQheF/oi'. - 'gF+JYWQKICkCJRA1vGtrDbxFbhGvY0HVjCLeS2BeTiHFgTB2wg'. - 'eRISstCnmcG2qCpbuXf3ADBQzWsPfZfS9y9HsEu4/Fo33Wf4Fx'. - 'gxL3a1XkI3wbTNXHLoboVeLFUYDqObYBy+Fw/Uh9DdCmtOwIjF'. - 'YvG76CZoOhNGRmpO8zz30CJoOhMAqlDxFzQLppgXj2XaNlP7FF'. - 'GLL7ccMYCBgZERgCvXLBrfi2DEclmiKZwFY4tp6sW26bVfnede'. - 'e5Hc5dC2bUgrXGKqWrwcXnNYDjmCrcCIiQgDcFYV05kQ8SXmnB'. - 'NgPiVN06wrTDGAhz5EWY/FOccTk+cTnHM/YNu2YYllgFxCWuUM'. - 'ikzGx+2Gc+4N+CoJW8n+5a2UKm2aBoBvGA6L7wfl8aoAAAAASU'. - 'VORK5CYII=' ; - - - //========================================================== - // File: pp_blue.png - //========================================================== - $this->imgdata_small[3][0]= 883 ; - $this->imgdata_small[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAACi1'. - 'BMVEX///8AAAAAADMAAGYAAJkAAMwAAP8zAAAzADMzAGYzAJkz'. - 'AMwzAP9mAABmADNmAGZmAJlmAMxmAP+ZAACZADOZAGaZAJmZAM'. - 'yZAP/MAADMADPMAGbMAJnMAMzMAP//AAD/ADP/AGb/AJn/AMz/'. - 'AP8AMwAAMzMAM2YAM5kAM8wAM/8zMwAzMzMzM2YzM5kzM8wzM/'. - '9mMwBmMzNmM2ZmM5lmM8xmM/+ZMwCZMzOZM2aZM5mZM8yZM//M'. - 'MwDMMzPMM2bMM5nMM8zMM///MwD/MzP/M2b/M5n/M8z/M/8AZg'. - 'AAZjMAZmYAZpkAZswAZv8zZgAzZjMzZmYzZpkzZswzZv9mZgBm'. - 'ZjNmZmZmZplmZsxmZv+ZZgCZZjOZZmaZZpmZZsyZZv/MZgDMZj'. - 'PMZmbMZpnMZszMZv//ZgD/ZjP/Zmb/Zpn/Zsz/Zv8AmQAAmTMA'. - 'mWYAmZkAmcwAmf8zmQAzmTMzmWYzmZkzmcwzmf9mmQBmmTNmmW'. - 'ZmmZlmmcxmmf+ZmQCZmTOZmWaZmZmZmcyZmf/MmQDMmTPMmWbM'. - 'mZnMmczMmf//mQD/mTP/mWb/mZn/mcz/mf8AzAAAzDMAzGYAzJ'. - 'kAzMwAzP8zzAAzzDMzzGYzzJkzzMwzzP9mzABmzDNmzGZmzJlm'. - 'zMxmzP+ZzACZzDOZzGaZzJmZzMyZzP/MzADMzDPMzGbMzJnMzM'. - 'zMzP//zAD/zDP/zGb/zJn/zMz/zP8A/wAA/zMA/2YA/5kA/8wA'. - '//8z/wAz/zMz/2Yz/5kz/8wz//9m/wBm/zNm/2Zm/5lm/8xm//'. - '+Z/wCZ/zOZ/2aZ/5mZ/8yZ///M/wDM/zPM/2bM/5nM/8zM////'. - '/wD//zP//2b//5n//8z///9jJVUgAAAAAXRSTlMAQObYZgAAAA'. - 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. - 'RQfTAwkWGTNerea3AAAAYUlEQVR4nHXNwQ3AIAxDUUfyoROxRZ'. - 'icARin0EBTIP3Hp1gBRqSqYo0seqjZpnngojlWBir5+b8o06lM'. - 'ha5uFKEpDZulV8l52axhVzqaCdxQp32qVSSwC1wN3fYiw7b76w'. - 'bN4SMue4/KbwAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: pp_green.png - //========================================================== - $this->imgdata_small[4][0]= 447 ; - $this->imgdata_small[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. - 'B3RJTUUH0wMJFhkLdq9eKQAAAUxJREFUeJyN1LFVwzAQxvH/8f'. - 'IeDS0FLKABlN6eIwPYAzCHB0gWYI2jj+i1ABUTQN4TRSQ7iiWZ'. - 'qxLn9Mt9ydmiqrSq930AYFiu6YdKrf/hP1gYQn6960PxwBaYMG'. - 'E9UA3dBFtVQjdBOQmBakLennK0CapRwbZRZ3N0O/IeEsqp3HKL'. - 'Smtt5pUZgTPg4gdDud+6xoS97wM2rsxxmRSoTgoVcMZsXJkBho'. - 'SmKqCuOuEtls6nmGMFPTUmxBKx/MeyNfQGLoOOiC2ddsxb1Kzv'. - 'ZzUqu5IXbGDvBJf+hDisi77qFSuhq7Xpuu66TyJLRGbsXVUPxV'. - 'SxsgkzDMt0mKT3/RcjL8C5hHnvJToXY0xYRZ4xnVKsV/S+a8YA'. - 'AvCb3s9g13UhYj+TTo93B3fApRV1FVlEAD6H42DjN9/WvzDYuJ'. - 'dL5b1/ji+/IX8EGWP4AwRii8PdFHTqAAAAAElFTkSuQmCC' ; - } -} - + 'imgdata_small', + MARK_IMG_SPUSHPIN => 'imgdata_small', + MARK_IMG_LPUSHPIN => 'imgdata_large'); + + protected $colors = array('blue','green','orange','pink','red'); + protected $index = array('red' => 0, 'orange' => 1, 'pink' => 2, 'blue' => 3, 'green' => 4 ) ; + protected $maxidx = 4 ; + protected $imgdata_large, $imgdata_small ; + + function __construct() { + + // The anchor should be where the needle "hits" the paper + // (bottom left corner) + $this->anchor_x = 0; + $this->anchor_y = 1; + + //========================================================== + // File: ppl_red.png + //========================================================== + $this->imgdata_large[0][0]= 2490 ; + $this->imgdata_large[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMKBh4Ryh89CgAACUdJREFUeJy9mNtTFFcexz+/7p'. + '4Lw1wZJKDGCAwmDAqUySamcCq1ed6k9mn3UfMP7F+1T3nYqn2J'. + 'lZdoDEjpbq0KG8EBFBFBEJye6Zmenkv32Ydu5GYiUMmeqq6uqT'. + '6Xz3zP73aOcIKmAQkIFyD3N/jrBPwlKjLQEglVlJKyUjR3u7cc'. + 'WLoP3/4dvv03LNrQ8I6x1rFbDML9kOmHvh7IRHU9JKmUSG8vpF'. + 'IoXX/TV0AiEM5A5jT0noFMFMJHXUt/d5f9TUAbhtQ3cPFruDog'. + '8klHMnmO0dGYe/myOJGINEwTz3F2higFXgy8PpAkOC+h8hoaCt'. + '4ppHFcQAWSgOQlyI/p+lUjmRxWAwNJd3xca/f34yoFi4tgmjtD'. + 'NIFkJ4xcgBCgVqEBFJ9DqcZea/gNAAVEg7AOGYnHe9XoaJd3+X'. + 'LISSSwnz6lsbKCZ9sHh4UVdBkwdA6cPwNnIfJPmC3Ctgft3wwQ'. + 'QPkvTZJJnbExzfvsM2nMzVG7e5fG48d4lnXwTwEYCjJxuHQBog'. + 'BHUfKkgAIIhiGk06hTp/Dm5qS1uYlXLvtWd4gPgIiCrAEcVckT'. + 'Ab5p7TaYJrK1hQaEenrwSiVfQdc91P0kSp7Ii89D5ksY/kAkLy'. + 'IZXFdXkQjS1YUSEbdcRu168V6+HTUNIKJDRwdE+sBIQmP9Ld59'. + 'bEBA3of4F/D+uXb7rGaaCSmXI3pPj64PDaHCYfEqFVSjgWo2D2'. + '73XlJNQTgCyQykIuBWoNKEeh1aLXBPBCggGdBOgxZVSjoajVhH'. + 'o5HWlIpq4bCQSgm9vXhK4ZZKh5SUYygp4J1EQVUD9xlU18BJQD'. + 'bUbJ5T5XJStyxN9fSI099P3baxV1dRloW2h2ivx/yakg2ot6F1'. + 'EkCa4G1D+zVEq5ArKTWM42Q6HUczQV7U66w9e0ZpdRXlOIQ5vF'. + 'VHUXILKify4jiEzkOqC3peQMoBQymFlMt4Dx6wUSxSsm2UZXEK'. + 'P30QvOUt8/2Sd78CdWwFDTA+gsw3cOlPcPUD+CQB52oQ21RKXM'. + 'eRhGXhOg7VoKrx8KuS4ygZhVg3ZI8FGIfwR9BVgAtfwxdXdP3L'. + '86nUR91dXelNXTeWWy10paQHX602YAP1ADASAL7LJvFtMpOCc0'. + 'cG3FHuGlz6Gr4YEpnoTCbzsdHRbOzy5RCRiLRMk5rjyOtAimwA'. + 'U4U3SurBN/0wnAASBCVDIKpB4kiAB5Ub0/UvO9LpPAMDGfn005'. + 'AxPCzxep3Q6iqPLUseBoufCZRsAE6g5g5kKIDfKUj3wnpAG8QB'. + '/Z1OIqANQuI65AtwNScyYXR2XlAXL2YZHzcklRKWl5GVFXFtGx'. + 'MoAiV/EQaAGH6BUQNWgQpwFngv+Ca8KUAQEBcwgTJHyMV7679R'. + 'XS8YqdSI6u/PMD5ukMtJY3GR2uQkr5aXeWVZOEALmA8WsIAxfL'. + 'd0goVLAdCOd+/YpgqeVtBv4yiA++q/RKKXixe7GB8PSyoljcVF'. + 'yg8fyubyMpulEk2lyAIfAAvAC+B+oOQFoAt/+0rAejB/EzjNri'. + 'vvqNnCd64jxcE39V8spnP+vMbAgDSePKE2NcXm06dslMuUlcID'. + 'TuFvqwXMBU8N39bGgRR+ki0Dz4L5DSAe9NGD7zq+6kcN1L6H2b'. + 'ao5WWaQHllRTafPmWrVMJUimoAQrBYJFjQwre7B6A8YAi8LCgD'. + '5DVo6/hbb/iHK1KggvFeD3hHziQKEMuiNTNDbXGRTdtmw7Iwla'. + 'KGH0oqwbscLOoG46rAY6AOzRhY74PT6QuUKEN4PegXxd/yEDTT'. + 'YMWOk+oEaLkuFdNk0zTZwjfkavDUArXWgGXgFb4dEShXhfYqlI'. + 'ow3w9rg3B6ED60IOOA5oEYQBrcpG+mj9bg0VG8GMJhVDZLyzAo'. + 'VSq8rFYxXXefcjVgG9+uisDrXUCApoKSBcUHMBmHhfcgNwhtD3'. + 'q9IG6Lr15b4OUTmPwBJt8JqGuapp05o0mhoHnptLQfPsR+8IBK'. + 'uYyNH3yr+B77LHheA3tK1Ta+IrMeTL2C6Xl48TOsNWDDgAz7s5'. + '/r+krP/eddCsbj8fDQ4GBm9MqVvvRXX2VULBayRGRzaYn1SoWa'. + 'UjgB4PIB5QK4ZgBXBKaAHxQsrED1H7CRgCUPwgHZDqACmhWwXv'. + '2aDRqGYeRyufS169cvThQKV88PDuYbW1vJ5VRK+5euqxWlPMdX'. + 'SRqgreHbZGN3ijfKBXBTAeh2Fdwi2MofshP/dvKwCmKhp4m83Y'. + 'vj8Xg4l8tlCoXC0MTExMTFkZE/1m37wvLGRvKRacoD1209E7Fc'. + 'pZwYREOQqEJ4z3HskHLsz4AoXykPIBSN0t3dTTQafROoHdumXC'. + '4fjoMiog0ODiauX7+eLxQKV3O53ETdti88nJnJ3rl505ifmWm3'. + 'arWSodR8GNbycDoNHy5C5jFold1k8d+DyvELNwg93d18/vnn9P'. + 'X1oes6nufx/Plz7t+/fxhQKSWJRCI5NjaWHxkZKdj1+sjSwkJm'. + '+uZN/dZ337VqCwullGUVdZjsgIUC5LqhrUPvCugWuApeApPAzY'. + 'PKHWyaphGNRunt7WVwcBARwfM8Ojo6sCzrMKBhGLphGFEF2Wq1'. + '2jc7M5OZ/vHH0MPbt93awkJJmeZsC6ZaMK3DCwvWdNioQUb5B6'. + 'AdBR+9SzkAz/NwHIeXL18iIui6TjgcJplMMjY2th8wHo+Hh4aG'. + 'MsPDw6fddru7+Phxx51bt/RbN260qwsLpZhlFZsw9QJ+2Pbrga'. + 'oJG2FY2oKwuTtVEz9uV34NbqdtbW0xPT1NNBoF4MyZM1y5coWu'. + 'rq5dQBHRcrlc4tq1a/l8Pj9RMs38ndu3Ez//9JNXLRZNyuXZJk'. + 'xVYKoExQpsK/+IaAuYb7no8zjC/R+A4zisrq7u+53NZjl16tQ+'. + 'QIlEIslsNpuPRCJXZ2dnh2/duNFRW1oy07a96MKd575yxRqU1B'. + '5vPMpF5HHa1tYW9+7do7Ozc/eQpZTSQ6FQt1Lq8pMnT/5w7969'. + 'nuLcXE1rNufO9fRMhlKpOyvt9qPtVmvb25fFfvvWbrepVCqHwo'. + 'xaX19vff/996ZhGC8qlkW9Wt1Onz073fXxxz+6MB+9e9dUjuO+'. + '7ebq9wLdB9hoNCrr6+s/4wf3FCJW3fPmTZhXsNWCprjuW66Dfr'. + '928KAfBhJAEgiJSLuzs7OSTqctoFkqlZRt26j/I+L/AGjPTN4d'. + 'Nqn4AAAAAElFTkSuQmCC' ; + + //========================================================== + // File: ppl_orange.png + //========================================================== + $this->imgdata_large[1][0]= 2753 ; + $this->imgdata_large[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQ0VCkHCzQAACk5JREFUeJytmGtzG0d2hp8zNw'. + 'AEcRdJ6EJK9FL0CqZUm9jWbkwq3vhDstl8dmLvz8rP2H8Q75ZT'. + 'pkRfpLgqsS6WIFEKGYkiSBCDO+banQ8DUpRWEkklXQUUqlCDfv'. + 'rp857pgfAOQ4AMOJdg4R/hX96Hf06bvDc5iT07i8yeg8ksiIAI'. + '4TBi/ds9/vivD/njapNHvRBfHXMu410AM+BUoVSF05NQsi1sO4'. + '8402AXwLQTuP31OAZO2aG0MEn14iSlnI1z3LnMk8IZYJyBwjIs'. + '/TWsVIWPJkvMFS4zMfMhUp5BsoCpAAEBLYKaMFGn00jBxnvu02'. + '35+JHmSJEnBpQEcPo38MmCxd/nS9Ry71Ga/g1W9a8gn0GsHkgA'. + '6DGjxkqb5CoO+YxF3A3p+jGjQUzoK+L/V0ADzFMwtSR8eLbAr8'. + 'uXOTf9NzhTc0geSLUQcYHgYEH786RMg0zWJHV2Aitv4x/HpHVS'. + 'QA2YBqTTGIUq5qkPMWaWkVwPnPtAA/BevmZcjxaaUtHh8pJJGu'. + 'DpCB9FvT7A7YT7S3p5vFMNzmWo/O0MSx/Ms3TqI8r59zFTfUQe'. + 'I7SBODE3tnfoIxYnNHligwik0zAzDdVpyKbA8sff5YAeMEwgkV'. + 'cufQeTJzZoCsaFLKXPTnNpoUTNsSgJmNoGsuNQjIDwYD2HlnZy'. + 'k++yxTKXZfKTU8zOpjhneeQYkorSmGERtIlICBKRbLX+y98YN3'. + 'ADcNIm+bJD4U3pPnmbEaRgYVRTGBkDSSsmxKfY7ZLuDJA4hdjl'. + 'JEgyBB2SJOvQ9RzTpNKoEwNq0CNFvOXR3/HxMgYVPObaz8kPmh'. + 'hkEWMatAfRONGGvLizyOE9P8KkpwhPDAgQKJQbELUD0oOIhbbH'. + 'JeVTmowxjAgZutB5AoOngA+2DdYrcTyOyYZP9+QpBvI29vwEhb'. + 'It042BVQgDy9KTMfkwQG1A9ACCLlgBBGUwxxoc52WDh2ATyEPp'. + '1hoaPvrEBh0Dq5an9OUsl/9hylk5b5c+mowLc4E2Jtw4Eoljyf'. + 'ogA/AGEAagNRjGyUxOmEycyVA5EWDBxrmUp3ytLIv/NJP69Goh'. + '+9mFydIvS5PZYkvH1oY/RFtKymlwBFQAgQd+kAA6qSQ8pvn2mp'. + 'SkJkuVFHPHBnQMrEt5Sl+e4/Lvp51PF1PF5Xy6WMvOWZXMom8z'. + 'OZTQ8+j5sbQiMEwopsCIwRtBGIJSCdzbTGo9NimkDcgdC7Bg49'. + 'TG5n4/nfr0Si77WdYp1YzyZEkWPdteaEnB7pPqBTxuIf/VgciE'. + 'SgasCPwh+GNIkaNNag1RiPge5pEhMQVjfoLcF+eoXSvbKxedwn'. + 'LKzC3KWbOi5/sW5a44/SHFUSgVA7SCzRG0AvA9mPOgFIETgu4n'. + 'Ww0wNQWFAqRSL6D2ZQYBdDrQ7R7jXiwgRcvIL02makuTmWtpM/'. + '+BlLMl5vuWzLVEuwH6oYnR1KS8kJINGXMM2YdfRlALoQoQQKeb'. + 'bDVwoMdxQMaLCwLo96HZTF5HbrEhmOftianfZisfzueKv7ZmrX'. + 'MsjhxKXZGBjzyeEHmSE3oWiggtyVGmE8DTIXTC5NxgAxOAGUM8'. + 'fun9mnSSLQ/CxNzOTgJ3LIMgoGwkKBiiMyaVviHVkdCO4FEKNv'. + 'LQzWBYHfITPa4UBVM0LR/WB7ARJsdDDTjA6deYFIFUOimJ3d0E'. + 'sNdLavYYgBpthqKcjiiJRO8K6CK0CsJTjfQAGaJtD9vQFAxNNQ'. + '1FB0yBAfA8gdMAIagLoCVAen0M00zMOTYShNDtoHs9CAIUoI4E'. + '1IBihCdNhsMhsj6NuV7BCC2IBpBqQaaFOENCCeiEsO1BO4RQgy'. + 'I5Hm4k4oIU9MrgZSAdBeTabZz+ODxKQRRBFBJo6IUc51anYRQo'. + 'dto+24FNxYCiaWKkQsj00KkO4gxRRkAngJ868M0u3OkkM+hxQA'. + 'cQ7YD7GO5XYSsPZybh/TCkFIYY+kWniTW4Q7jXgHvHMhiRpmuW'. + 'ca08GZkkZ/nY6TZMNhCnf2CuPoDVJvxpB+q9BHA8Ag1uH+oP4c'. + 'YEPCzDwmzSLquShHW/E0YRbG/BjZtw40hAy7aNzJlzRn75E6N0'. + 'qiwTzafI7kOU3gWrhzZC2iHcbsPqLlxvJnCt4KC1RYAL3I5hzY'. + 'Xv/huePYCtITQMKEnyB4KQvMURuJvw889HGSwUCs7CwkLpo6tX'. + 'Ty/+7nel6VLGDn/8N9m+eZuo1UP8iNhLau6b3RfmOsHBGTUYw9'. + 'WBNeDrGB4+h/4qNLKwTnLbHj9CJw/6GoIh9Jpvq0HHcayFhYXi'. + 'l3/4w9LK8vLKexfma3G/mb/3n1njTivS7tNQaaU1grQDjJ868D'. + 'Axx6vmxnBrY9C9IcSbSXbavNjb/S3eN6/0m1JcKBScixcvllZW'. + 'Vi6uLC8v12q1v/M8b/HxVjP//YYr32yE4dYWvShO0ogi14xwxq'. + 'F4rbnxZ3cMjtpvEEeMvwA0TdOYn5/PffHFF7Vr166tvPeLXyx7'. + 'nrd4+/btyg/frFo//Xgncnd67qCn78earQqcmYD3fSi1wPCTSV'. + '3gzqvm9uFOMl5nUAqFQn5paal26dKla57vf7D+6FHph9VV88af'. + 'vgq79bo70e3VT2l9A3hYg4UiRALVHTCHSZvYBm4A//6quf8zoG'. + '3bpuM4acMwKr1+//SDe/dK31+/bv90/Xrcq9fduNW6rbVeC+E7'. + 'gWdD2DKg4UEpBmPcm10RuScida31ntb62HAigoigDw6Gh0axWH'. + 'QWFhZKi4uLZ+I4PrVer2e+u37dXPvqq6hbr7tOp1NXWq89h6/b'. + '8FBB34WGBesdcPrj38lkMkGlUuml0+mu53nR3t4eo9HoSLhMJk'. + 'OlUiGdTuN5Hq7rvgA0TdO4cOFC7vPPP6/VarXldqdTu7m2lrv7'. + '7beq++BBO263b/tKrfWSXlbvwJ6CuAtDgTYiaBFMw6BSqfDxxx'. + '+rarWqGo0GN2/eZGtrC6XenAkRoVKpcPXqVWZmZmg0Gty6desF'. + 'oIhIOp3Ol8vlmmVZK3fv3Lm09uc/Zwbr653ccPgoNIzvnmn99Z'. + '7W9QG46lAaM5mM2l95GIYUi0VOnz7N7OwsWmsymQzyuse5Q8Mw'. + 'DNLpNDMzM5w/f/7A6AGgUkoajYa9urpayOXzUz/fvZutr68Pim'. + 'F4/2y1+n2o9Q/ru7uPesPhXnyo4A+vfHp6mmazybNnz9jZ2UFr'. + 'TbPZJAhe+8/aS0Mphed5NBoNABqNBqPR6MWBVWstvu/nnj9/Pv'. + 'vo0aPq5uZmPBgM/qcwPf39xV/9ajU1M3Nvq9PZaw8GoT50PjdN'. + 'k6mpKa5cucL58+eJ45j19XWePHnCzs4OnudhmiaWZRGGIVH05r'. + 'yEYYjrumxubrKxsfFyDQJ6NBp1Pc+7C4jWumBaVm+kVL2l1H2l'. + '1G6otS+H6V6z8u3tbVzXpdFooJRicXGRqakptre3uXXr1ltrcT'. + 'Qa8ezZszemWAE9rfUdYBOwtVLRbrPZ+48ff+wDvuu6Sr3MB4Dr'. + 'uty6desgfa1WC3iRyrNnz4pSSmezWUzTfGtYtNYcdvC/9sMlgP'. + 'n5N4cAAAAASUVORK5CYII=' ; + + //========================================================== + // File: ppl_pink.png + //========================================================== + $this->imgdata_large[2][0]= 2779 ; + $this->imgdata_large[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQolY9lkpgAACmhJREFUeJy9mOtzFNl5h5+3b9'. + 'Mz0kzPBWmEVtIiWYhIiC0HCDhB8lb8ISk7nzdZ5+/zJ/8BTmpT'. + '660CZLwG1pVFgBkgGIHECEaa+/T9nHzQCCQuRpCNz6mp6g893U'. + '8/c37ve3qEjxiC4OA4n/Lp/EUu/tsMM/+aEWduVBx7WhdkShcY'. + 'xUH2zo0Dwod/5N6vf8V//PoGdx8M8EOFPtK9jI8BdHCcMuVSmf'. + 'LxHLmSZdm2U8xIbmKETDGDZZnIy4dBbCynyGhphurEDBOlHFnn'. + 'qPcyPxTOwDCOccw7w5nlBRZWylI+ny/mZ6rL1dzUZ5/IWGZU3D'. + 'ZIOMQDDaJcHDVGWUbJBi9odVr0QoVSPzigIEaZ8vgSS/8wZU3/'. + 'k1fylipz5dLM2WlrZqHKaGCKbEbontq3KAKWQyZfZKTgYqc9Bp'. + '2I2PcJ4ogk/UEBQcwipbFZmT13vDBx8fhnE1Ofnp9yJopFyT3X'. + 'yANfks0QHSQMDaL37pOxMLIu2UyVkjVKLjyKSeuD8dAYCFkso1'. + 'gYMaeWJ40T56cl8yAi/O4FSa2P6kYczIDsgVpAqcDImZPMuAB1'. + 'dkLQtcc8a/bwox8IUHAxZVxGZMouSLVYwKuMkD5IxN+JSdsRJB'. + 'pexuTVgYYM6EoGmxkmg3/hEhNUMr/hd7dqbOzExMn/GRDAxWZc'. + 'j3I8HiXfMjF2FQowKw7pjoN6E/Llw/GBJj8qxVOMlX4ipxc/lY'. + 'kl2zBLkmrTcEzMkoNoRLVidLi/9g+Z3I+1xRHX5EcAihxnbPRv'. + 'OTU9kZSmpKPy9FTGrLimPZ1H+UiyGaF67w6n7E1DwMngFDxGvc'. + 'w70v0xZUby5IxjlIyMssUJrJwVWkXBdbXvSvwEibcSdKCAFI16'. + '4/sc0SRo9cGAGq1DwvQFzV6DVuBiV4zYnlEts6A2TSPcSiXoxo'. + 'QqJCEEFMbQ2b69o5qMiOOPqIMQkagu/aSL7waE8101WFShLjk9'. + 'yxgEvjRUiyYd+gwAjY2J9VpXfZ/JEXLhDp3OR6U4T97+hEnPwx'. + 'tv4HsRjy2tTQSFzQgDUnwSLBQRI+x1ZgcH87Vcv4SF19Kt0ezS'. + '1h9s0Ma25pgr/YJfnLnEysok0+ezjM6EBLldGqKIJYuDRhOQEJ'. + 'Oih8X9Q0xmcXNjlCofBJgn78wxVz7L2YWf8tPPz1hnfjbjzfxN'. + 'qVwutq2etZXUQSXikcXGIgUiUkJSDIQMJgYGJsaB3c7b1qQ4GZ'. + 'xSkdGZIwMeNLfK6uezMnvJK3pLxeVixfvMsyVjSNSO6IV9adPG'. + 'AArkEEz8oUkFmBjYGO80qfd6pCWIayD59wIKcsjcKqufn7JO/S'. + 'xfyi+5c24pey5rZ09mJRNkiDdT/tzbkBr3SYkpMYpgEaIJSYhI'. + 'kSOY1GhilAQk5ntDIojxCZ/kf87Pl85xbuWEnLiUy+cW3NNuJX'. + 'MmY5meKf6mT7wZS+THdOjxlG06tIlIOMZxchSxcFFEGAwAGGME'. + 'jwyZYSnWL3cXWiIUbUI6hO/vxXuFOV84ycmlBWthNeflTjuzTi'. + 'lzJmM5s46Ej0J63/ZoPmoy6PYxtYVNhmfs0mbAND1mmKVMBY1L'. + 'mxA1LN7WgXQbCApNhKJHRIM+DQbv7yQGhjnJ5NgFuXBuxpu5mD'. + 'udm3LPuY7pmZLUE6L1SIJaIPFuDAqyw9lnwDYv6NFHkWJh4ZDB'. + 'wCBFD3uMxsTAwcBAiElpE/KcPg36dIiOvpsRxDCyhmlP2YY9ZU'. + 'v8NMb/1id+FGO0DTztkSXLOONUqeITsMkW2zwnJEIDFhYGx+A1'. + 'kwK4mASkvKDPc3p0iYhRRwYUhZLUTyV6Eu0t4s1Y4kcx6W6KaM'. + 'EZThcXH59RRhGEgIAddnBwNEBKqqpUtWBIF22YDIhJsbEkJqFN'. + 'qLtERHs7GnUkwISEQAf0uj30bY39PzbiC6qrDu2cExJ69Nhhhz'. + '59UlIUipCQOnVi4sjG7ubJBy6um0C+he/0iDHQKIQERYyKFLqr'. + 'SI/W6kJCnvOcrWSLSquC1/Jw9Ks3R0FQKHr0uMc9bnCDGjX69A'. + 'H0XlcJkibN5jOe/alCZStHbjJL9lSMLkXExvCXRiDV6GZEeGeX'. + '3TvvBVQoEjfBL/v0rT75Th7VU5C8gktI6NLlMY+5yU3WWGODDf'. + 'r098tHpNFNH7/2lKdXXdz7efLzVaqJIBOCmK8AJUlI6g0aV+9y'. + '9+p7AR3bMQpTBWPy7yeN6fy0jNwewfpvC9Xe+3kFoUuXe9zj5n'. + 'BusEGHjh6GIAGawC2FWuvSvbbF1maFylZAsC1ISZADBiVNSJrP'. + 'eX73MY//skHP85z5+fnSxQsXj//4n39cmnPn7LbZlsajBmEnBL'. + '1nuEGDG9x4aa5Ldz+h0RCuBqwBv1Wo+7vs9r7n++0MmYeAM+zB'. + '+61EK1QUEnbbtN+9Bh3Hsebn54u//PdfLq9eWl2ZnZ1dSnaSwu'. + 'Pin40b9g3doKE0WoNIl65xj3v75njd3BBubQi6ExKmDWkMRKSl'. + 'tSbVKQcMao1Go5Ugb0+x53nOyZMnSysrKydXLq1cWlxa/McgCB'. + 'Yev3hU+GPrD3I5/q94k3pXYQY58q6B5Bs0HB//neaGx00gyWaz'. + 'VCoV7bquCoKAnZ0dfN/f03egLGj0m3XQNE1jdnY2/+WXXy6trq'. + '6uzP3oR5eCIFi4detW5feXL1vr679Let37zVB3/mQytjXJwmSB'. + 'wikHp9ShY0RESqObwPrr5oBERKhUKly4cIFqtUq9XufmzZtsbW'. + '2hXvuDwTTNtxZq8TyvsLy8vLS4uLgahOHphw8elL69fNlc++qr'. + 'uFOrNXPddm1cczVL5f5P+Lv5MuOJgTGxwYbZpZsCdeAq8M1Bcw'. + 'CGYeC6LtVqlRMnTjAyMkKn0yGXyx0N0LZt03Ec1zCMSrfXO37v'. + 'zp3S769csb+/ciXt1mrNdHf3ltZ6Lca8ZpJsduhtCdb2gEFJoQ'. + 'xADYHuHDS3f32lFEEQUK/XGRkZoVAocP78eZaXl9FaI/Jq25Uk'. + 'yWHAYrHozM/PlxYWFibTND32sFbLXrtyxVz76qukXas1M61WTW'. + 'm99gx+20TdN9jqtfjP7QzOwwYNp037Zd0DukDnIByA1pqdnR2+'. + '++472u02Z8+eZWJiAsMwDsEBRNGBzYJpmsaJEyfyX3zxxdLS0t'. + 'KlVqu1dP3q1cLta9ekU6u1dat1J9b6Sk9kraV1rYXegW7apDYw'. + 'kFY6fPc4MNTw88bwfZ/NzU2UUnieRxAEiAiGcXiXfcigiIjruo'. + 'VyubxkWdbK7fX1xWvffFMInjzBM82uMT5+p++6V1UUrSe7u03t'. + '+8lezlKt3gHyl0aSJDQaDa5fv876+vo+w6FzDq1BpZRsb2/bly'. + '9f9vL5/Njdu3fzG0+eMJHNxsfn532vXN5NPG/7abPZal6/Hvfe'. + 'kroPHfsm98f7AHW9Xo+//vrrlmVZm71+37QNw3JnZ9PK4uJGpV'. + 'pt4Dh+vLGhsrmcfv1iHzu01m89HjIdCon2fb8TBMHtvYeRUn50'. + '1Oj4vqp3Ok1f5LYSadfr9dQfDN642P/XeF2DA+SBAuA4jkOhUK'. + 'BQKESO43S11p3BYBDt7u4y+CtB/i/q7jp1GMiw2AAAAABJRU5E'. + 'rkJggg==' ; + + //========================================================== + // File: ppl_blue.png + //========================================================== + $this->imgdata_large[3][0]= 2284 ; + $this->imgdata_large[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFRAiTZAL3gAACHlJREFUeJy9mGtv29YZgJ9zKF'. + 'F3y/Q9jh05tuQkarKgbYasde0UBdZgwNou/Vqga/sD9mP2B4a1'. + 'BbZ9atFPxb5sqOtmXbI19bqsluPYiR3HN90vFEWRZx/IJI5zqa'. + 'x0OwBBSgR5Hj7v+55zSEFXTUgIJyA9C6/9RsjMjAyFIxxJCDc7'. + 'iBqKgyZACGg3G2x9+xXf/fG33P3mC9qNKsp1O+1JdkEnQTdgIO'. + 'ttCSMUi8gj072MnugllAyB9G8rBGi6RsToJTF6iuRoFi1kHKZf'. + '7fB8Iggj0/Dy23D2dakNTR3JDsXPvzstxmZGRMER1EwHhQAEgE'. + 'CLhIkPD6InY9S3djGLJVBtQP1Qb4HDAyoJYQOOZkPx49nhTH9i'. + '7MUBGT7egxkJgd70wZS/CUkoZtA/fRoE1DZ2ACiv52ibReCp4e'. + '7CIEHomxDiuVdGTqUnf/ZeOjR8fpiVXZul5ZrY3bWwbdcLr/dA'. + 'AAIpAwQjUWIjQ+g9HZvswiCgBVF9/SI6OSLGzo0i+oLi6+Utbq'. + '+bKEftgwOE/0Ohocf66M+cBjo22U2RQLIHMhmYnvaOpR9S8bSU'. + 'UqCURGpRkuMZMm9cIvPGJZLj0yBjT2LprkiSkykx9cuXIhOnUs'. + 'm+QNC2XdG02ggBTcvFabsPWwTPpBAChSCgh4kYBpoeplWp47Qs'. + '7EYDt21xINzd5GCAxLExRl89Z+nHjpbKMmjbmkgfDzI0JEW53K'. + 'Jaa6NcAOEX8v52uJzsBlAS6u0hcnTIccPRqhWPCUcLD+s1EaUp'. + 'HCEhEMCyHNpt9SjgIU12A6iw6xb123vYhaaKjB9tlgMD5X+uBp'. + 'zdkpg6azA8EaNQtKlVba+Xez4eCntnJrsDdFsW5nYFpxlFN846'. + 'DXe8utkM4mhi+EgQmjYbS2WqexZKk6BpjwJ2YlK5VjeA3pNDiH'. + 'YjRWPzPE7tmBo8EWwGhkXx+z3uXL7D3rU97LIF8RBEAl6lK/Uo'. + '6JNM1rZ2aTcr3eUgIQOGTgbdwXMGyRejenLYTvQGbAdRuetSud'. + 'OivVuFZgtCEgICghICnZoMhmlVTPR49LCAEkQUhk/B7KXe0MWf'. + 'nxj8xVR/cDheK14WZmtVMJSBnlGoN6FmQq0FLfdwJgORKPHRo/'. + 'Snzx4G0F/FjJ4KiOdmjPCrrx8bffnMybMv9MQGNG3rzlVqtR1B'. + 'sh/CYXCD4Aag1oCW7ZnUOjSp6WFi/QNEB8Y7BfTNjZyCmUvJ0I'. + 'XXT47MTp98Ybon9VZCk8cVazfqlNargsY34G7ByAlIjkHd9CCr'. + 'LbBdiHViUgiECuDKYCdz8b2cywREdiYZOj8zNnLuzOTzx6ODp+'. + 'OaGaqwVzBFqz0Idhz2loE7YEwBLaAJLQcKbW8qjAcBF5Jh0AMP'. + 'IOHe6kxgtb3UMO2OxkF//ffK28nQqxfvm3szrtnDVa799Qb/+v'. + 'NtsbNSpm3tAv8B+w7Ub0FhAyoBcMPec9oK6raXk48ziQBXQcmC'. + 'pT3YqHa0mpEBkTR6wz/Jjo2cy04+fzwxdDquNfQKO7sFUbpu0c'. + 'wp3JoAYsA42Bbkl4GCryUNDEM7Avm6Z/CgSYBWG8pNuFuDu1Wo'. + 'tjoxKIJGeHIiM/jmK9NnX5ycuJQMtUcqXPvLDTa+qIie4hAJ1U'. + 'vdrmO2HaDfB931twJgAn1A4lGT96obPHPLBbhVgUoTHHWo9aAA'. + 'JVAKpyKEmQNzWRENAsL18ycKjAFN/9gCNvzLB/390MMmE7pnDi'. + 'Bvwt0K5Jv3O+0oB22nJ1Vvjb/UMhOpcKknqN1OiMB2DNHU2G5s'. + 'sVndpGJVcZXjX1IAlvw9PmhRQcOFPhsSDkiBrQR1G7brgs0a7D'. + 'ag3FK4rguqBXarI4Nt1SJv5gls7TEWtJDRBO2GwnIs8maevFnA'. + 'Gx6awLZvzeTBu4kFbLigijC47pscpx0xyDfkvtUEnlarCDtrUC'. + 't2HGIhvPHVdVwqjTIrxRU2a5uUrYoP0QZ2gMvACl7+3V/LuKDq'. + 'sJuDy597516+CEezIHXv7vcgXQu2l+Bvn8He9Y4AE4kgk5P9DE'. + 'R6aFdq5Et5Nit3yTf3m9sBcsAN3+D98c0Fit5JawE25r1zg1Fo'. + '5B8GFD7g+nVYnu8EUEop9XTa0N/9dUbqcphP/rDJzbUClVbpgR'. + 'y2fXM3fND95qj75J8AC6BWPINfVSBieK+x+6cS5UCzCLu3oFV9'. + 'GqCMx2NGOp2Znpv7aXZudsool3T5J/179sxVlHJ4kGPrP2COBX'. + '/7DmiApWCjxIMXpYNznYuXM+6TAKWUMppOZzLvv//ery5cuDCT'. + 'SqVS336bCwr1JfAPB9r+2KAFwJS+OcETzZHz/7v3etl6ipz77X'. + 'GAMh6PG+l0OjM3NzczOzs3k0pNnFlbW43+e/GKtMqrblSsF03V'. + 'WHcJA0PjIAzvg9JTze2H67g9DjAwOTmZ+uCDD96anZ2dnZiYmF'. + '5dW41++Lvfa1fnr7qllVK9103mXNTnJgPA+YugsvB3HTaEl+Qs'. + 'AZ/yeHPPDCiTyaRx5syZbGoilV1dW00szC9oV+avusuLy0Xd0X'. + 'MgFkDM+zkYBZEHV8f7wwKu84zmngQoNU0LaZoWUa4K31y5qX/8'. + '4cfyyvwVN5/L10NOKNeg8UmDxoKF5Vfj1xXAgD0JrgAcvBDfel'. + 'a4g4AykUgY6XR6emJiIru2ttZXq9S0K19eUcuLy8WQE8o5OAsN'. + 'Ggsmpl+NpoL1g9X4UBU+C9xDgEKIwNTUVOqdd955M9mbnJ3/cj'. + '6Vu5aTheXCQXNdVeMzAwJSCGEA2XKpnF1cXIzlFnOVhJPIKdR+'. + 'c88ctq4AlVKsrKzw0UcfKcC5uXqzXnNqSzb2pwLxOHP/l7Z/BN'. + 'eB01LKt4HTrusKvGr8jB+hGn8MQAkYQMrfw4Nq/MFPtf+rdvDb'. + 'k8QL+/5Z4Uepxm7bfwHuTAVUWpWaqAAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: ppl_green.png + //========================================================== + $this->imgdata_large[4][0]= 2854 ; + $this->imgdata_large[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQ4hANhluwAACrNJREFUeJytmF1zE1eagJ+3u9'. + 'XdkvUty2AbmLEtEzDBgZ0UpDBOalNTUzU3czl7tct/2n+wt3M/'. + 'NVM12SSTQQSyW2TA+QAJQogtYYFtyfrqL3WfvWj5g8AEjzfvhS'. + 'SXjk8//Zz3Pf3qCMcJAWxMKlT4kH+jwu/FknnJSUItKFHzCrKA'. + 'BggBQx5ziz/wn/yBz3hED4/oaJfSjgVoYjJJgTLTZCjohp7IGT'. + 'k5aZ4kb+bRTR30Q7djj8f/kpPMUSCFedRL6W8e8qMQNE6S4xpv'. + 'c5HrTPFubiJ3ZnlyOXV59rJYU5Z00h1c3d0brxAiUkScRijisk'. + '6XLTyiN3s8HuAJpniXa/q8/pt8Or+0kF8oXJm5YiydWcIpOrJu'. + 'rjOQwd54AQwsMpTJYhPSoYuLQ58An/DnBQSdImXO8avsTPbqpc'. + 'lLp67OXDVzMznZLGxSs2qyIRu4at8gKHQEC50kE1icxqCAdxST'. + 'xjEA44tqaJlERl8uLWvvnX5PHuQfcCdxh5qq0aX76vj4WgWyXO'. + 'QiNgBP8IAaddr08X8+wHFmJSQhBbPAZGoSZSt5wQs6qoNC7UEd'. + '4AEoLIQSCaCCy78Dv8Tiv1hjjW1CRj8XIAgEKqDtt9keboMJZa'. + 'vMjuzQVd3Xr9prTJo+GF/jKZea95R25Lxs8jg5qFGiwDnOS0mW'. + 'NE0rjNRIt3WbklUCA9mV3Zdz8OBT/JfCQLB0SKYVVjGFYSfx/E'. + '26ow4e6uDujlPFQpE0FU6P8qNTHdXJdEdda0qf0itWBVM3pa/3'. + 'ccUlIECJet0cAJoeYk5EZCeS5IwEoerSxccJBwRqFFf38QCTaO'. + 'TRVFKJm3NTbtLNSyh2IkhIXsvLCesEGNCWdmwyruSD/z9kUlRc'. + '3bqNlSxhJNJ43p5JITrOEis8Qtr0cXEpU/JT/pmO18n2vb42pU'. + '3JnDnHMBqyPlpnoAaxhr2llv1ZUBqEGlqYwDQMsskMOcMgVL3Y'. + 'ZOQTHAcQQiIGjHCwCaiovjrv4hbcpKuJJjIcDHm685RGr4GLCx'. + 'YHkAcrLoAoDSLBiAQrMkjqybHJCbxgh+7xAC1MpsgzwRwD3qHL'. + 'WyTIBdlAa6u2rHfXaew06PV78ZZjAwleNnkolECoH5i090wOcY'. + '+TgwYzFHiPi1zkOkXexeAMASnVU+LiyiA1wFUuaqggACLizeWw'. + 'ycMzyssmVYKkbpGyC5T+OUALk2mKLHKWf+ED/az+YW42d66YL+'. + 'aNrmEEzQCFEnKw368EgEvcN1m80eTIQIt0TFOjMJHkzNEBBYPp'. + 'sblf8QHzrORO5JaWZ5ZLl6cuJyyxpNPv4PZdoT+GyIxBfI5uUg'. + 'eJMCwP2/bIHO1JEudcgUUWOceKNq99mCvnzs5PzRcuTV4y5mRO'. + 'SMIjo47z5S7a94oQCNKgJsZwO7D/IDNg3/LLhRNXt4JohBb4aG'. + '82GLdXcf93mQ+Y43r2RHZp+cRy6cqJK4l8MS+tdItaqiYtc0Mm'. + 'QpfJARh98HYh9IiXVcaAo58wGb+LBAjbSPgCOcoSa0wzxXtc08'. + '/pv8mfyL+9MLVQvDJ1JVHJV6SZbFI1qtTsB+KlehRtRTGE8Afo'. + 'P4DRcAxiEudhAHjjzz+ubgX4oHowakHQOlqzICQwyVPITGVOXi'. + 'xfLF6aumzmczl5lHzMff2+fCdPaGttEkXoLQAO9B7C6EugPYby'. + 'gVPjGXc5eIbNAJPjGwiAbaAJUQv8wVG7GROkJFpyOqn/ovgLba'. + '44L0+sDaraXb6jzq7aBQWjBOyUoHcaopOgmaA3IRyNDZnA1HjO'. + 'HSBkr7eEFDAEngHrQCf+/s2A8cSiSkqcKUeeTjwFy2Jd78t3+L'. + 'TR4itIiBLwLQhzkJyB5Cx4HXDaENVQCBAQcRqFIHTRaBIvuYXg'. + 'AdsouuNxEL0ZUBHnSQp66R73zYfUtQ6OytKT8RckQAJQoLtgO5'. + 'BJgj0D/WfgdyHaAHx8THoUcbGx8ciwhUl3bDEiToURPooeI7pH'. + 'MziK9Yd9nU5a6GgKjOH41vsgI4hAcyC5AZkapF+AoYNrjjsuhx'. + 'FbtPmeB5ykyQQzTPAWAQWC8S9oAI0QRRuPb9jkmyMZNAOTklvC'. + 'GGYZaFkGmkVAh8h4DtKFMIBunG+pB5B5AIkGBDsQ+qBiL20caj'. + 'zhJknq5KlgMkLjJHJos4kYEbFJi5vc5eYbATVN02bNWe19+32t'. + 'aJWlFm3wbf8Rz5NbDFJdlOFBF/g7cBf0JkrbBb+F6j1DOduEkU'. + '8bWCOiSofPWadBnSZDWmgUkEMGhZCINut8S/0NBtPptFlZrBSu'. + 'vnt1+ndnflfIp9OJ/279Ubbbd+lP7KBKPoEBsgnqLph/BRzwdS'. + 'LnBUFvHcfdpRsGPAGqwMco6jynz+e0SPKYCHMfLX5VKHwcenR+'. + 'Igd1XTcqlUr+xn/cePv91fevzy8sLO2OtrOpWkqL7gXKSAVRdh'. + 'ZFEmEXoYkwBNqovoc/3GHH3aUR+jwC1oD/AWrANi4hGwyBzqEG'. + 'Vvb77Dgi0eT1VZzJZMxKpVJYXV1dXF1dXVm6sPSvruue3Xzcyj'. + '6/syvDzwj0lNazK6Fj5LFCRZouZpBABj6jXouu3+Np6HNvDHaf'. + 'g91t74msbMuOJicnSSaTKKUQEUQEpRSO69But1/dB0VEm5uby9'. + 'y4cWNpdXX1+sLCworrume//PuXpeqnVeOban0U1PW2kcx+O9L7'. + 'Te9sUB4lWFR9SqNtNGcHx+/RDD2+Am4D94CnQA8OjjlEhMnyJC'. + 'srK8zOzu7BiYioMAzZ2Njg9u3brwIqpSSXy2WXl5eXLly4sOo4'. + 'zoV6vV6oflrVP/7Tx8Hmw1Zb6ydqmpWp7ha8h4O3gjOhzVANmF'. + 'XPMNQWvdDnCXCXuHR+APqH4fbCtm2mp6eZn59H13WJuYXRaKSU'. + 'UiSTyVcBdV3XDcOwRaTU7/en19bWCn/79G+JL/76RbhZ22y7u+'. + '6ahl71nPDz/nO17m7wAxlabFOihy4+DvAcqAMbPzZ3OFzX5dmz'. + 'Z2iahoiosUUVhiGNRgPHcV4GzGQy5uLiYuH8+fMzo9FoslarJW'. + '9+elP75E+fBJu1zY7qqpqBUW3T/niohnVvy+1zm5aVtp+WE2XT'. + 'nrHFzbjh1tYLz3XdPjD4R3BKKba2tqhWq4dzUO3noBPn4H5PKy'. + 'LaO++8U7hx48byhQsXVne7u6tf3/v64t3P7mbq9+odt+OuaWi3'. + 'PLxbW2ytubjbQCgiMnt6VlaurWgz0zM0m02q1WrUaDSUUuqI56'. + 'ivDxE5MCgiYllWtlwuL5mmufLV/a/O/uXPf9Ff1F+80Lv6Yx29'. + '2qHzyZBh3cdvc7gaTZuZkzPh/Py8ACqVSv1/uPZDKXUAGEWRtF'. + 'qtxEcffZTL5XLF+2v39fqjeivshA/TpP83JLwzYFBzcA4370Cc'. + 'S81nTRBUs9lkOByi1GuOPI4Rh3+26JZlnSkWi781DOPXvV4v3+'. + '/2G0R8kSBxB/jew+tERK+c49m2TblcxrZtXNfl+fPneJ6HZVmU'. + 'y2VJJpNyaJ9TSinlOA5bW1u4rntkQA0oAG8D54gb9W3ianxM3A'. + 'e/cn73U3Hq1Cm5du2aPjs7a+ztcSIShmE4ajQa6tatWzQajZ+0'. + 'fbiKI+It4SvijVUj7kL2qvGfgkskEqTTaZmcnDROnTplJhIJTU'. + 'QiwPd9P/Q8T6XTaQzDIAiCfzjP/wFVfszuFqdHXgAAAABJRU5E'. + 'rkJggg==' ; + + + //========================================================== + // File: pp_red.png + //========================================================== + $this->imgdata_small[0][0]= 384 ; + $this->imgdata_small[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhouFobZrQAAAQ1JREFUeJyV1dFtwyAQBuD/og'. + 'xQdYxa8gRY6hJ0jK6QdohMkTEuE5wUj5ERen05IoLvID7Jkn2G'. + 'j8MgTMyMXqRlUQBYq9ydmaL2h1cwqD7l30t+L1iwlbYFRegY7I'. + 'SHjkEifGg4ww3aBa/l4+9AhxWWr/dLhEunXUGHq6yGniw3QkOw'. + '3jJ7UBd82n/VVAlAtvsfp98lAj2sAJOhU4AeQ7DC1ubVBODWDJ'. + 'TtCsEWa6u5M1NeFs1NzgdtuhHGtj+9Q2IDppQUAL6Cyrlz0gDN'. + 'ohSMiJCt861672EiAhEhESG3woJ9V9OKTkwRKbdqz4cHmFLSFg'. + 's69+LvAZKdeZ/n89uLnd2g0S+gjd5g8zzjH5Y/eLLi+NPEAAAA'. + 'AElFTkSuQmCC' ; + + //========================================================== + // File: pp_orange.png + //========================================================== + $this->imgdata_small[1][0]= 403 ; + $this->imgdata_small[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhwAnApz5AAAASBJREFUeJyN1dFthDAMBuDf7S'. + '3BCm2VCRKpS4QxbhikW6IewzcBqm6Fm6JyH7iEEByCn5AJH38g'. + 'BBIRHNUzBAWAGNfe/SrUGv92CtNt309BrfFdMGPjvt9CD8Fyml'. + 'ZZaDchRgA/59FDMD18pvNoNyHxMnUmgLmPHoJ+CqqfMaNAH22C'. + 'fgqKRwR+GRpxGjXBEiuXDBWQhTK3plxijyWWvtKVS5KNG1xM8I'. + 'OBr7geV1WupDqpmTAPKjCqLhxk/z0PImQmjKrAuI6vMXlhFroD'. + 'vfdqITXWqg2YMSJEAFcReoag6UXU2DzPG8w5t09YYsAyLWvHrL'. + 'HUy6D3XmvMAAhAay8kAJpBosX4vt0G4+4Jam6s6Rz1fgFG0ncA'. + 'f3XfOQcA+Acv5IUSdQw9hgAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: pp_pink.png + //========================================================== + $this->imgdata_small[2][0]= 419 ; + $this->imgdata_small[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhsQzvz1RwAAATBJREFUeJyd1MFthDAQheF/oi'. + 'gF+JYWQKICkCJRA1vGtrDbxFbhGvY0HVjCLeS2BeTiHFgTB2wg'. + 'eRISstCnmcG2qCpbuXf3ADBQzWsPfZfS9y9HsEu4/Fo33Wf4Fx'. + 'gxL3a1XkI3wbTNXHLoboVeLFUYDqObYBy+Fw/Uh9DdCmtOwIjF'. + 'YvG76CZoOhNGRmpO8zz30CJoOhMAqlDxFzQLppgXj2XaNlP7FF'. + 'GLL7ccMYCBgZERgCvXLBrfi2DEclmiKZwFY4tp6sW26bVfnede'. + 'e5Hc5dC2bUgrXGKqWrwcXnNYDjmCrcCIiQgDcFYV05kQ8SXmnB'. + 'NgPiVN06wrTDGAhz5EWY/FOccTk+cTnHM/YNu2YYllgFxCWuUM'. + 'ikzGx+2Gc+4N+CoJW8n+5a2UKm2aBoBvGA6L7wfl8aoAAAAASU'. + 'VORK5CYII=' ; + + + //========================================================== + // File: pp_blue.png + //========================================================== + $this->imgdata_small[3][0]= 883 ; + $this->imgdata_small[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAACi1'. + 'BMVEX///8AAAAAADMAAGYAAJkAAMwAAP8zAAAzADMzAGYzAJkz'. + 'AMwzAP9mAABmADNmAGZmAJlmAMxmAP+ZAACZADOZAGaZAJmZAM'. + 'yZAP/MAADMADPMAGbMAJnMAMzMAP//AAD/ADP/AGb/AJn/AMz/'. + 'AP8AMwAAMzMAM2YAM5kAM8wAM/8zMwAzMzMzM2YzM5kzM8wzM/'. + '9mMwBmMzNmM2ZmM5lmM8xmM/+ZMwCZMzOZM2aZM5mZM8yZM//M'. + 'MwDMMzPMM2bMM5nMM8zMM///MwD/MzP/M2b/M5n/M8z/M/8AZg'. + 'AAZjMAZmYAZpkAZswAZv8zZgAzZjMzZmYzZpkzZswzZv9mZgBm'. + 'ZjNmZmZmZplmZsxmZv+ZZgCZZjOZZmaZZpmZZsyZZv/MZgDMZj'. + 'PMZmbMZpnMZszMZv//ZgD/ZjP/Zmb/Zpn/Zsz/Zv8AmQAAmTMA'. + 'mWYAmZkAmcwAmf8zmQAzmTMzmWYzmZkzmcwzmf9mmQBmmTNmmW'. + 'ZmmZlmmcxmmf+ZmQCZmTOZmWaZmZmZmcyZmf/MmQDMmTPMmWbM'. + 'mZnMmczMmf//mQD/mTP/mWb/mZn/mcz/mf8AzAAAzDMAzGYAzJ'. + 'kAzMwAzP8zzAAzzDMzzGYzzJkzzMwzzP9mzABmzDNmzGZmzJlm'. + 'zMxmzP+ZzACZzDOZzGaZzJmZzMyZzP/MzADMzDPMzGbMzJnMzM'. + 'zMzP//zAD/zDP/zGb/zJn/zMz/zP8A/wAA/zMA/2YA/5kA/8wA'. + '//8z/wAz/zMz/2Yz/5kz/8wz//9m/wBm/zNm/2Zm/5lm/8xm//'. + '+Z/wCZ/zOZ/2aZ/5mZ/8yZ///M/wDM/zPM/2bM/5nM/8zM////'. + '/wD//zP//2b//5n//8z///9jJVUgAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAwkWGTNerea3AAAAYUlEQVR4nHXNwQ3AIAxDUUfyoROxRZ'. + 'icARin0EBTIP3Hp1gBRqSqYo0seqjZpnngojlWBir5+b8o06lM'. + 'ha5uFKEpDZulV8l52axhVzqaCdxQp32qVSSwC1wN3fYiw7b76w'. + 'bN4SMue4/KbwAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: pp_green.png + //========================================================== + $this->imgdata_small[4][0]= 447 ; + $this->imgdata_small[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhkLdq9eKQAAAUxJREFUeJyN1LFVwzAQxvH/8f'. + 'IeDS0FLKABlN6eIwPYAzCHB0gWYI2jj+i1ABUTQN4TRSQ7iiWZ'. + 'qxLn9Mt9ydmiqrSq930AYFiu6YdKrf/hP1gYQn6960PxwBaYMG'. + 'E9UA3dBFtVQjdBOQmBakLennK0CapRwbZRZ3N0O/IeEsqp3HKL'. + 'Smtt5pUZgTPg4gdDud+6xoS97wM2rsxxmRSoTgoVcMZsXJkBho'. + 'SmKqCuOuEtls6nmGMFPTUmxBKx/MeyNfQGLoOOiC2ddsxb1Kzv'. + 'ZzUqu5IXbGDvBJf+hDisi77qFSuhq7Xpuu66TyJLRGbsXVUPxV'. + 'SxsgkzDMt0mKT3/RcjL8C5hHnvJToXY0xYRZ4xnVKsV/S+a8YA'. + 'AvCb3s9g13UhYj+TTo93B3fApRV1FVlEAD6H42DjN9/WvzDYuJ'. + 'dL5b1/ji+/IX8EGWP4AwRii8PdFHTqAAAAAElFTkSuQmCC' ; + } +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/imgdata_squares.inc.php b/ext/jpgraph-3.0.7/src/imgdata_squares.inc.php index 8c76de3..15ddc02 100644 --- a/ext/jpgraph-3.0.7/src/imgdata_squares.inc.php +++ b/ext/jpgraph-3.0.7/src/imgdata_squares.inc.php @@ -1,150 +1,150 @@ -'imgdata'); - - protected $colors = array('bluegreen','blue','green', - 'lightblue','orange','purple','red','yellow'); - protected $index = array('bluegreen' =>2,'blue'=>5,'green'=>6, - 'lightblue'=>0,'orange'=>7,'purple'=>4,'red'=>3,'yellow'=>1); - protected $maxidx = 7 ; - protected $imgdata ; - - function ImgData_Squares () { - //========================================================== - //sq_lblue.png - //========================================================== - $this->imgdata[0][0]= 362 ; - $this->imgdata[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAAABm'. - 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. - 'B3RJTUUH0wMLFgojiPx/ygAAAPdJREFUeNpj/P377+kzHx89/c'. - 'VAHNBQ5VBX52HavPWWjg6nnDQbkXoUFTnnL7zD9PPXrz17HxCj'. - 'E6Jn6fL7H7/+ZWJgYCBGJ7IeBgYGJogofp1oehDa8OjE1IOiDa'. - 'tOrHoYGBhY0NwD0enirMDAwMDFxYRVD7ptyDrNTAU0NXix6sGu'. - 'jYGBgZOT9e/f/0xMjFyczFgVsGAKCfBza2kKzpl3hIuT1c9Xb/'. - 'PW58/foKchJqx6tmy98vbjj8cvPm/afMnXW1JShA2fNmQ9EBFc'. - 'Opnw6MGjkwm/Hlw6mQjqwaqTiRg9mDoZv//4M2/+UYJ64EBWgj'. - 'cm2hwA8l24oNDl+DMAAAAASUVORK5CYII=' ; - - //========================================================== - //sq_yellow.png - //========================================================== - $this->imgdata[1][0]= 338 ; - $this->imgdata[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAWl'. - 'BMVEX////+/+H+/9/9/9v8/8P8/8H8/7v8/7n6/4P5/335/3n5'. - '/3X4/1f4/1P3/031/w30/wn0/wPt+ADp9ADm8ADk7gDc5gDa5A'. - 'DL1ADFzgCwuACqsgClrABzeAC9M0MzAAAAAWJLR0QAiAUdSAAA'. - 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEDlOgDj'. - 'EAAAB+SURBVHjaVcpbCsQgDEDRGERGKopjDa2a/W9zfLWj9/Nw'. - 'Ac21ZRBOtZlRN9ApzSYFaDUj79KIorRDbJNO9bN/GUSh2ZRJFJ'. - 'S18iorURBiyksO8buT0zkfYaUqzI91ckfhWhoGXTLzsDjI68Sz'. - 'pGMjrzPzauA/iXk1AtykmvgBC8UcWUdc9HkAAAAASUVORK5CYI'. - 'I=' ; - - //========================================================== - //sq_blgr.png - //========================================================== - $this->imgdata[2][0]= 347 ; - $this->imgdata[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAZl'. - 'BMVEX////0+vv0+vrz+fry+frv+Png7e/d7e/a6+zY6+250tSz'. - '0tSyztCtztGM0NWIz9SDzdNfsLVcrrRZrbJOp61MpqtIr7dHn6'. - 'RErrZArLQ6q7M2g4kygYcsp68npa4ctr8QZ20JnqepKsl4AAAA'. - 'AWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU'. - '1FB9MDCxYEByp8tpUAAAB7SURBVHjaVcjRFoIgDADQWZpWJpjY'. - 'MsnG//9kzIFn3McLzfArDA3MndFjrhvgfDHFBEB9pt0CVzwrY3'. - 'n2yicjhY4vTSp0nbXtN+hCV53SHDWe61dZY+/9463r2XuifHAM'. - '0SoH+6xEcovUlCfefeFSIwfTTQ3fB+pi4lV/bTIgvmaA7a0AAA'. - 'AASUVORK5CYII=' ; - - //========================================================== - //sq_red.png - //========================================================== - $this->imgdata[3][0]= 324 ; - $this->imgdata[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. - 'BMVEX////++Pn99/j99ff99fb98/X98/T98PL55uj43+P24+bw'. - 'kKPvjaHviJ3teJHpxMnoL2Pjs73WW3rWNljVWXnUVnbUK1DTJk'. - '3SUHPOBz/KQmmxPVmuOFasNFOeIkWVka/fAAAAAWJLR0QAiAUd'. - 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEHd'. - 'ceT+8AAABtSURBVHjaVchbAkMwEAXQq6i3VrQiQfa/zDYTw8z5'. - 'PCjGt9JVWFt1XWPh1fWNdfDy+tq6WPfRUPENNKnSnXNWPB4uv2'. - 'b54nSZ8jHrMtOxvWZZZtpD4KP6xLkO9/AhzhaCOMhJh68cOjzV'. - '/K/4Ac2cG+nBcaRuAAAAAElFTkSuQmCC' ; - - //========================================================== - //sq_pink.png - //========================================================== - $this->imgdata[4][0]= 445 ; - $this->imgdata[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAApV'. - 'BMVEX////6+Pz69/v49Pr38/r17/jr4+/l3Onj2efh1ua/L+i+'. - 'q8m+Lue9Lua8qsS8LuW8LeS7pca5LOG4LN+2Y9O2YNW1ZdO1Kt'. - 'y0atC0aNGzb82zbc6zKtuzKdqycsuwa8qtJtOISZ2GRpuFN6GE'. - 'NqCDQpmCMZ+BPpd/LJ1/K519S5B9Jpx9Jpt9JZt6RY11BJZ1BJ'. - 'V0BJV0BJRzBJNvNoRtIoJUEmdZ/XbrAAAAAWJLR0QAiAUdSAAA'. - 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYDF3iKMD'. - 'YAAACeSURBVHjaVczbEoIgGARgCiMtrexoWpaa2FHUgvd/tH4Y'. - 'BnEvv9ldhNPradPnnGBUTtPDzMRPSIF46SaBoR25dYjz3I20Lb'. - 'ek6BgQz73Il7KKpSgCO0pTHU0886J1sCe0ZYbALjGhjFnEM2es'. - 'VhZVI4d+B1QtfnV47ywCEaKeP/p7JdLejSYt0j6NIiOq1wJZIs'. - 'QTDA0ELHwhPBCwyR/Cni9cOmzJtwAAAABJRU5ErkJggg==' ; - - //========================================================== - //sq_blue.png - //========================================================== - $this->imgdata[5][0]= 283 ; - $this->imgdata[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAQl'. - 'BMVEX////4+fz39/z19vvy8vru7/ni4+7g4fHW1ue8vteXmt6B'. - 'hdhiZ7FQVaZETcxCSJo1Oq4zNoMjKakhJHcKFaMEC2jRVYdWAA'. - 'AAAWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0'. - 'SU1FB9MDCxYDN0PkEP4AAABfSURBVHjaVchHAoAgDATAVcCCIF'. - 'j4/1elJEjmOFDHKVgDv4iz640gLs+LMF6ZUv/VqcXXplU7Gqpy'. - 'PFzBT5qml9NzlOX259riWHlS4kOffviHD8PQYZx2EFMPRkw+9Q'. - 'FSnRPeWEDzKAAAAABJRU5ErkJggg==' ; - - //========================================================== - //sq_green.png - //========================================================== - $this->imgdata[6][0]= 325 ; - $this->imgdata[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. - 'BMVEX////2+vX1+vX1+fT0+fPz+PPx9/Dv9u7u9e3h7uHe697a'. - '6dnO2s3I1sa10LOvza2ay5aEwYBWlE9TqE5Tkk1RkEpMrUJMg0'. - 'hKiUNGpEFBojw8oTcsbScaYBMWlwmMT0NtAAAAAWJLR0QAiAUd'. - 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEFd'. - 'nFx90AAABuSURBVHjaVc9HAoAgDADB2HuJWLDx/2cKBITscW4L'. - '5byzMIWtZobNDZIZtrcCGZsRQ8GwvRSRNxIiMuysODKG3alikl'. - 'ueOPlpKTLBaRmOZxQxaXlfb5ZWI9om4WntrXiDSJzp7SBkwMQa'. - 'FEy0VR/NAB2kNuj7rgAAAABJRU5ErkJggg==' ; - - //========================================================== - //sq_orange.png - //========================================================== - $this->imgdata[7][0]= 321 ; - $this->imgdata[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAUV'. - 'BMVEX/////8+n/8uf/8OP/59H/5Mv/zqH/zJ3/ypv/yJf/vYH/'. - 'u33/uXn/n0n/nUX/m0H/lzn/ljf/lDP/kS3/kCv/iR//hxv/fg'. - 'n/fAX/eQDYZgDW6ia5AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAL'. - 'EgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEJIgbx+cAAAB2SURBVH'. - 'jaVczRCoQwDETRbLAWLZSGUA35/w/dVI0283i4DODew3YESmWW'. - 'kg5gWkoQAe6TleUQI/66Sy7i56+kLk7cht2N0+hcnJgQu0SqiC'. - '1SzSIbzWSi6gavqJ63wSduRi2f+kwyD5rEukwCdZ1kGAMGMfv9'. - 'AbWuGMOr5COSAAAAAElFTkSuQmCC' ; - } -} - +'imgdata'); + + protected $colors = array('bluegreen','blue','green', + 'lightblue','orange','purple','red','yellow'); + protected $index = array('bluegreen' =>2,'blue'=>5,'green'=>6, + 'lightblue'=>0,'orange'=>7,'purple'=>4,'red'=>3,'yellow'=>1); + protected $maxidx = 7 ; + protected $imgdata ; + + function ImgData_Squares () { + //========================================================== + //sq_lblue.png + //========================================================== + $this->imgdata[0][0]= 362 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFgojiPx/ygAAAPdJREFUeNpj/P377+kzHx89/c'. + 'VAHNBQ5VBX52HavPWWjg6nnDQbkXoUFTnnL7zD9PPXrz17HxCj'. + 'E6Jn6fL7H7/+ZWJgYCBGJ7IeBgYGJogofp1oehDa8OjE1IOiDa'. + 'tOrHoYGBhY0NwD0enirMDAwMDFxYRVD7ptyDrNTAU0NXix6sGu'. + 'jYGBgZOT9e/f/0xMjFyczFgVsGAKCfBza2kKzpl3hIuT1c9Xb/'. + 'PW58/foKchJqx6tmy98vbjj8cvPm/afMnXW1JShA2fNmQ9EBFc'. + 'Opnw6MGjkwm/Hlw6mQjqwaqTiRg9mDoZv//4M2/+UYJ64EBWgj'. + 'cm2hwA8l24oNDl+DMAAAAASUVORK5CYII=' ; + + //========================================================== + //sq_yellow.png + //========================================================== + $this->imgdata[1][0]= 338 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAWl'. + 'BMVEX////+/+H+/9/9/9v8/8P8/8H8/7v8/7n6/4P5/335/3n5'. + '/3X4/1f4/1P3/031/w30/wn0/wPt+ADp9ADm8ADk7gDc5gDa5A'. + 'DL1ADFzgCwuACqsgClrABzeAC9M0MzAAAAAWJLR0QAiAUdSAAA'. + 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEDlOgDj'. + 'EAAAB+SURBVHjaVcpbCsQgDEDRGERGKopjDa2a/W9zfLWj9/Nw'. + 'Ac21ZRBOtZlRN9ApzSYFaDUj79KIorRDbJNO9bN/GUSh2ZRJFJ'. + 'S18iorURBiyksO8buT0zkfYaUqzI91ckfhWhoGXTLzsDjI68Sz'. + 'pGMjrzPzauA/iXk1AtykmvgBC8UcWUdc9HkAAAAASUVORK5CYI'. + 'I=' ; + + //========================================================== + //sq_blgr.png + //========================================================== + $this->imgdata[2][0]= 347 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAZl'. + 'BMVEX////0+vv0+vrz+fry+frv+Png7e/d7e/a6+zY6+250tSz'. + '0tSyztCtztGM0NWIz9SDzdNfsLVcrrRZrbJOp61MpqtIr7dHn6'. + 'RErrZArLQ6q7M2g4kygYcsp68npa4ctr8QZ20JnqepKsl4AAAA'. + 'AWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU'. + '1FB9MDCxYEByp8tpUAAAB7SURBVHjaVcjRFoIgDADQWZpWJpjY'. + 'MsnG//9kzIFn3McLzfArDA3MndFjrhvgfDHFBEB9pt0CVzwrY3'. + 'n2yicjhY4vTSp0nbXtN+hCV53SHDWe61dZY+/9463r2XuifHAM'. + '0SoH+6xEcovUlCfefeFSIwfTTQ3fB+pi4lV/bTIgvmaA7a0AAA'. + 'AASUVORK5CYII=' ; + + //========================================================== + //sq_red.png + //========================================================== + $this->imgdata[3][0]= 324 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. + 'BMVEX////++Pn99/j99ff99fb98/X98/T98PL55uj43+P24+bw'. + 'kKPvjaHviJ3teJHpxMnoL2Pjs73WW3rWNljVWXnUVnbUK1DTJk'. + '3SUHPOBz/KQmmxPVmuOFasNFOeIkWVka/fAAAAAWJLR0QAiAUd'. + 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEHd'. + 'ceT+8AAABtSURBVHjaVchbAkMwEAXQq6i3VrQiQfa/zDYTw8z5'. + 'PCjGt9JVWFt1XWPh1fWNdfDy+tq6WPfRUPENNKnSnXNWPB4uv2'. + 'b54nSZ8jHrMtOxvWZZZtpD4KP6xLkO9/AhzhaCOMhJh68cOjzV'. + '/K/4Ac2cG+nBcaRuAAAAAElFTkSuQmCC' ; + + //========================================================== + //sq_pink.png + //========================================================== + $this->imgdata[4][0]= 445 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAApV'. + 'BMVEX////6+Pz69/v49Pr38/r17/jr4+/l3Onj2efh1ua/L+i+'. + 'q8m+Lue9Lua8qsS8LuW8LeS7pca5LOG4LN+2Y9O2YNW1ZdO1Kt'. + 'y0atC0aNGzb82zbc6zKtuzKdqycsuwa8qtJtOISZ2GRpuFN6GE'. + 'NqCDQpmCMZ+BPpd/LJ1/K519S5B9Jpx9Jpt9JZt6RY11BJZ1BJ'. + 'V0BJV0BJRzBJNvNoRtIoJUEmdZ/XbrAAAAAWJLR0QAiAUdSAAA'. + 'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYDF3iKMD'. + 'YAAACeSURBVHjaVczbEoIgGARgCiMtrexoWpaa2FHUgvd/tH4Y'. + 'BnEvv9ldhNPradPnnGBUTtPDzMRPSIF46SaBoR25dYjz3I20Lb'. + 'ek6BgQz73Il7KKpSgCO0pTHU0886J1sCe0ZYbALjGhjFnEM2es'. + 'VhZVI4d+B1QtfnV47ywCEaKeP/p7JdLejSYt0j6NIiOq1wJZIs'. + 'QTDA0ELHwhPBCwyR/Cni9cOmzJtwAAAABJRU5ErkJggg==' ; + + //========================================================== + //sq_blue.png + //========================================================== + $this->imgdata[5][0]= 283 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAQl'. + 'BMVEX////4+fz39/z19vvy8vru7/ni4+7g4fHW1ue8vteXmt6B'. + 'hdhiZ7FQVaZETcxCSJo1Oq4zNoMjKakhJHcKFaMEC2jRVYdWAA'. + 'AAAWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0'. + 'SU1FB9MDCxYDN0PkEP4AAABfSURBVHjaVchHAoAgDATAVcCCIF'. + 'j4/1elJEjmOFDHKVgDv4iz640gLs+LMF6ZUv/VqcXXplU7Gqpy'. + 'PFzBT5qml9NzlOX259riWHlS4kOffviHD8PQYZx2EFMPRkw+9Q'. + 'FSnRPeWEDzKAAAAABJRU5ErkJggg==' ; + + //========================================================== + //sq_green.png + //========================================================== + $this->imgdata[6][0]= 325 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'. + 'BMVEX////2+vX1+vX1+fT0+fPz+PPx9/Dv9u7u9e3h7uHe697a'. + '6dnO2s3I1sa10LOvza2ay5aEwYBWlE9TqE5Tkk1RkEpMrUJMg0'. + 'hKiUNGpEFBojw8oTcsbScaYBMWlwmMT0NtAAAAAWJLR0QAiAUd'. + 'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEFd'. + 'nFx90AAABuSURBVHjaVc9HAoAgDADB2HuJWLDx/2cKBITscW4L'. + '5byzMIWtZobNDZIZtrcCGZsRQ8GwvRSRNxIiMuysODKG3alikl'. + 'ueOPlpKTLBaRmOZxQxaXlfb5ZWI9om4WntrXiDSJzp7SBkwMQa'. + 'FEy0VR/NAB2kNuj7rgAAAABJRU5ErkJggg==' ; + + //========================================================== + //sq_orange.png + //========================================================== + $this->imgdata[7][0]= 321 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAUV'. + 'BMVEX/////8+n/8uf/8OP/59H/5Mv/zqH/zJ3/ypv/yJf/vYH/'. + 'u33/uXn/n0n/nUX/m0H/lzn/ljf/lDP/kS3/kCv/iR//hxv/fg'. + 'n/fAX/eQDYZgDW6ia5AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAL'. + 'EgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEJIgbx+cAAAB2SURBVH'. + 'jaVczRCoQwDETRbLAWLZSGUA35/w/dVI0283i4DODew3YESmWW'. + 'kg5gWkoQAe6TleUQI/66Sy7i56+kLk7cht2N0+hcnJgQu0SqiC'. + '1SzSIbzWSi6gavqJ63wSduRi2f+kwyD5rEukwCdZ1kGAMGMfv9'. + 'AbWuGMOr5COSAAAAAElFTkSuQmCC' ; + } +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/imgdata_stars.inc.php b/ext/jpgraph-3.0.7/src/imgdata_stars.inc.php index 6b59a77..42eeecc 100644 --- a/ext/jpgraph-3.0.7/src/imgdata_stars.inc.php +++ b/ext/jpgraph-3.0.7/src/imgdata_stars.inc.php @@ -1,144 +1,144 @@ - 'imgdata'); - - protected $colors = array('bluegreen','lightblue','purple','blue','green','pink','red','yellow'); - protected $index = array('bluegreen'=>3,'lightblue'=>4,'purple'=>1, - 'blue'=>5,'green'=>0,'pink'=>7,'red'=>2,'yellow'=>6); - protected $maxidx = 7 ; - protected $imgdata ; - - function __construct() { - //========================================================== - // File: bstar_green_001.png - //========================================================== - $this->imgdata[0][0]= 329 ; - $this->imgdata[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAAUV'. - 'BMVEX///////+/v7+83rqcyY2Q/4R7/15y/1tp/05p/0lg/zdX'. - '/zdX/zVV/zdO/zFJ9TFJvDFD4yg+8Bw+3iU68hwurhYotxYosx'. - 'YokBoTfwANgQFUp7DWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. - 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJj'. - 'CRyxgTAAAAcUlEQVR4nH3MSw6AIAwEUBL/IKBWwXL/g0pLojUS'. - 'ZzGLl8ko9Zumhr5iy66/GH0dp49llNPB5sTotDY5PVuLG6tnM9'. - 'CVKSIe1joSgPsAKSuANNaENFQvTAGzmheSkUpMBWeJZwqBT8wo'. - 'hmysD4bnnPsC/x8ItUdGPfAAAAAASUVORK5CYII=' ; - //========================================================== - // File: bstar_blred.png - //========================================================== - $this->imgdata[1][0]= 325 ; - $this->imgdata[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v79uRJ6jWPOSUtKrb+ejWO+gWPaGTruJTr6rZvF2'. - 'RqC2ocqdVuCeV+egV/GsnLuIXL66rMSpcOyATbipY/OdWOp+VK'. - 'aTU9WhV+yJKBoLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJwynv1'. - 'XVAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bstar_red_001.png - //========================================================== - $this->imgdata[2][0]= 325 ; - $this->imgdata[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v7+eRFHzWG3SUmHnb37vWGr2WHG7Tlm+TljxZneg'. - 'Rk3KoaXgVmXnV2nxV227nJ++XGzErK3scIS4TVzzY3fqWG2mVF'. - 'zVU2PsV2rJFw9VAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJzCI0C'. - 'lSAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bstar_blgr_001.png - //========================================================== - $this->imgdata[3][0]= 325 ; - $this->imgdata[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v79Ehp5Yx/NSq9Jvw+dYwu9YzfZOmbtOmb5myPFG'. - 'gqChvcpWteBXvedXxvGcsbtcpb6su8RwzOxNmrhjyvNYwupUjK'. - 'ZTr9VXwOyJhmWNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJTC65k'. - 'vQAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bstar_blgr_002.png - //========================================================== - $this->imgdata[4][0]= 325 ; - $this->imgdata[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v79EnpxY8/FS0dJv5+dY7+9Y9vBOubtOur5m8fFG'. - 'nKChycpW3uBX5+ZX8e2curtcvrqswsRw7OdNuLZj8/BY6udUpK'. - 'ZT1dRX7OtNkrW5AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJgXHeN'. - 'wwAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bstar_blue_001.png - //========================================================== - $this->imgdata[5][0]= 325 ; - $this->imgdata[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v79EY55Yi/NSetJvledYiO9YkPZOb7tObr5mkvFG'. - 'X6ChrcpWgOBXhedXi/Gcpbtcf76sssRwnOxNcbhjk/NYiepUbK'. - 'ZTfdVXh+ynNEzzAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJhStyP'. - 'zCAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bstar_oy_007.png - //========================================================== - $this->imgdata[6][0]= 325 ; - $this->imgdata[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v7+ejUTz11jSvVLn02/v1lj21li7q06+r07x2mag'. - 'lUbKxKHgy1bnz1fx1Ve7t5y+qlzEwqzs03C4pE3z2WPqz1imml'. - 'TVv1Ps01dGRjeyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJjsGGc'. - 'GbAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - - //========================================================== - // File: bstar_lred.png - //========================================================== - $this->imgdata[7][0]= 325 ; - $this->imgdata[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. - 'BMVEX///+/v7+eRJPzWN3SUr7nb9TvWNj2WOS7Tqi+TqnxZtyg'. - 'Ro/KocPgVsjnV9LxV927nLa+XLTErL7scN24TarzY9/qWNemVJ'. - 'jVU8LsV9VCwcc9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. - 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJxi9ZY'. - 'GoAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. - 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. - 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. - 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; - } -} - + 'imgdata'); + + protected $colors = array('bluegreen','lightblue','purple','blue','green','pink','red','yellow'); + protected $index = array('bluegreen'=>3,'lightblue'=>4,'purple'=>1, + 'blue'=>5,'green'=>0,'pink'=>7,'red'=>2,'yellow'=>6); + protected $maxidx = 7 ; + protected $imgdata ; + + function __construct() { + //========================================================== + // File: bstar_green_001.png + //========================================================== + $this->imgdata[0][0]= 329 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAAUV'. + 'BMVEX///////+/v7+83rqcyY2Q/4R7/15y/1tp/05p/0lg/zdX'. + '/zdX/zVV/zdO/zFJ9TFJvDFD4yg+8Bw+3iU68hwurhYotxYosx'. + 'YokBoTfwANgQFUp7DWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJj'. + 'CRyxgTAAAAcUlEQVR4nH3MSw6AIAwEUBL/IKBWwXL/g0pLojUS'. + 'ZzGLl8ko9Zumhr5iy66/GH0dp49llNPB5sTotDY5PVuLG6tnM9'. + 'CVKSIe1joSgPsAKSuANNaENFQvTAGzmheSkUpMBWeJZwqBT8wo'. + 'hmysD4bnnPsC/x8ItUdGPfAAAAAASUVORK5CYII=' ; + //========================================================== + // File: bstar_blred.png + //========================================================== + $this->imgdata[1][0]= 325 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79uRJ6jWPOSUtKrb+ejWO+gWPaGTruJTr6rZvF2'. + 'RqC2ocqdVuCeV+egV/GsnLuIXL66rMSpcOyATbipY/OdWOp+VK'. + 'aTU9WhV+yJKBoLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJwynv1'. + 'XVAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_red_001.png + //========================================================== + $this->imgdata[2][0]= 325 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+eRFHzWG3SUmHnb37vWGr2WHG7Tlm+TljxZneg'. + 'Rk3KoaXgVmXnV2nxV227nJ++XGzErK3scIS4TVzzY3fqWG2mVF'. + 'zVU2PsV2rJFw9VAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJzCI0C'. + 'lSAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_blgr_001.png + //========================================================== + $this->imgdata[3][0]= 325 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79Ehp5Yx/NSq9Jvw+dYwu9YzfZOmbtOmb5myPFG'. + 'gqChvcpWteBXvedXxvGcsbtcpb6su8RwzOxNmrhjyvNYwupUjK'. + 'ZTr9VXwOyJhmWNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJTC65k'. + 'vQAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_blgr_002.png + //========================================================== + $this->imgdata[4][0]= 325 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79EnpxY8/FS0dJv5+dY7+9Y9vBOubtOur5m8fFG'. + 'nKChycpW3uBX5+ZX8e2curtcvrqswsRw7OdNuLZj8/BY6udUpK'. + 'ZT1dRX7OtNkrW5AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJgXHeN'. + 'wwAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_blue_001.png + //========================================================== + $this->imgdata[5][0]= 325 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79EY55Yi/NSetJvledYiO9YkPZOb7tObr5mkvFG'. + 'X6ChrcpWgOBXhedXi/Gcpbtcf76sssRwnOxNcbhjk/NYiepUbK'. + 'ZTfdVXh+ynNEzzAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJhStyP'. + 'zCAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_oy_007.png + //========================================================== + $this->imgdata[6][0]= 325 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+ejUTz11jSvVLn02/v1lj21li7q06+r07x2mag'. + 'lUbKxKHgy1bnz1fx1Ve7t5y+qlzEwqzs03C4pE3z2WPqz1imml'. + 'TVv1Ps01dGRjeyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJjsGGc'. + 'GbAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + + //========================================================== + // File: bstar_lred.png + //========================================================== + $this->imgdata[7][0]= 325 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+eRJPzWN3SUr7nb9TvWNj2WOS7Tqi+TqnxZtyg'. + 'Ro/KocPgVsjnV9LxV927nLa+XLTErL7scN24TarzY9/qWNemVJ'. + 'jVU8LsV9VCwcc9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJxi9ZY'. + 'GoAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + } +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpg-config.inc.php b/ext/jpgraph-3.0.7/src/jpg-config.inc.php index 35081fa..0eea4d5 100644 --- a/ext/jpgraph-3.0.7/src/jpg-config.inc.php +++ b/ext/jpgraph-3.0.7/src/jpg-config.inc.php @@ -1,132 +1,132 @@ - + diff --git a/ext/jpgraph-3.0.7/src/jpgraph.php b/ext/jpgraph-3.0.7/src/jpgraph.php index fa5696d..7237f1e 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph.php +++ b/ext/jpgraph-3.0.7/src/jpgraph.php @@ -1,5401 +1,5401 @@ -Get(11,$file,$lineno); - die($msg); - } - else { - define('CACHE_DIR', $_SERVER['TEMP'] . '/'); - } - } else { - define('CACHE_DIR','/tmp/jpgraph_cache/'); - } - } -} -elseif( !defined('CACHE_DIR') ) { - define('CACHE_DIR', ''); -} - -// -// Setup path for western/latin TTF fonts -// -if (!defined('TTF_DIR')) { - if (strstr( PHP_OS, 'WIN') ) { - $sroot = getenv('SystemRoot'); - if( empty($sroot) ) { - $t = new ErrMsgText(); - $msg = $t->Get(12,$file,$lineno); - die($msg); - } - else { - define('TTF_DIR', $sroot.'/fonts/'); - } - } else { - define('TTF_DIR','/usr/share/fonts/truetype/'); - } -} - -// -// Setup path for MultiByte TTF fonts (japanese, chinese etc.) -// -if (!defined('MBTTF_DIR')) { - if (strstr( PHP_OS, 'WIN') ) { - $sroot = getenv('SystemRoot'); - if( empty($sroot) ) { - $t = new ErrMsgText(); - $msg = $t->Get(12,$file,$lineno); - die($msg); - } - else { - define('MBTTF_DIR', $sroot.'/fonts/'); - } - } else { - define('MBTTF_DIR','/usr/share/fonts/truetype/'); - } -} - -// -// Check minimum PHP version -// -function CheckPHPVersion($aMinVersion) { - list($majorC, $minorC, $editC) = preg_split('/[\/.-]/', PHP_VERSION); - list($majorR, $minorR, $editR) = preg_split('/[\/.-]/', $aMinVersion); - - if ($majorC != $majorR) return false; - if ($majorC < $majorR) return false; - // same major - check minor - if ($minorC > $minorR) return true; - if ($minorC < $minorR) return false; - // and same minor - if ($editC >= $editR) return true; - return true; -} - -// -// Make sure PHP version is high enough -// -if( !CheckPHPVersion(MIN_PHPVERSION) ) { - JpGraphError::RaiseL(13,PHP_VERSION,MIN_PHPVERSION); - die(); -} - -// -// Make GD sanity check -// -if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) { - JpGraphError::RaiseL(25001); - //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)"); -} - -// -// Setup PHP error handler -// -function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) { - // Respect current error level - if( $errno & error_reporting() ) { - JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); - } -} - -if( INSTALL_PHP_ERR_HANDLER ) { - set_error_handler("_phpErrorHandler"); -} - -// -// Check if there were any warnings, perhaps some wrong includes by the user. In this -// case we raise it immediately since otherwise the image will not show and makes -// debugging difficult. This is controlled by the user setting CATCH_PHPERRMSG -// -if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) { - JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']); -} - -// Useful mathematical function -function sign($a) {return $a >= 0 ? 1 : -1;} - -// -// Utility function to generate an image name based on the filename we -// are running from and assuming we use auto detection of graphic format -// (top level), i.e it is safe to call this function -// from a script that uses JpGraph -// -function GenImgName() { - // Determine what format we should use when we save the images - $supported = imagetypes(); - if( $supported & IMG_PNG ) $img_format="png"; - elseif( $supported & IMG_GIF ) $img_format="gif"; - elseif( $supported & IMG_JPG ) $img_format="jpeg"; - elseif( $supported & IMG_WBMP ) $img_format="wbmp"; - elseif( $supported & IMG_XPM ) $img_format="xpm"; - - - if( !isset($_SERVER['PHP_SELF']) ) { - JpGraphError::RaiseL(25005); - //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); - } - $fname = basename($_SERVER['PHP_SELF']); - if( !empty($_SERVER['QUERY_STRING']) ) { - $q = @$_SERVER['QUERY_STRING']; - $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format; - } - else { - $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format; - } - return $fname; -} - -//=================================================== -// CLASS JpgTimer -// Description: General timing utility class to handle -// time measurement of generating graphs. Multiple -// timers can be started. -//=================================================== -class JpgTimer { - private $start, $idx; - - function __construct() { - $this->idx=0; - } - - // Push a new timer start on stack - function Push() { - list($ms,$s)=explode(" ",microtime()); - $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; - } - - // Pop the latest timer start and return the diff with the - // current time - function Pop() { - assert($this->idx>0); - list($ms,$s)=explode(" ",microtime()); - $etime=floor($ms*1000) + (1000*$s); - $this->idx--; - return $etime-$this->start[$this->idx]; - } -} // Class - -//=================================================== -// CLASS DateLocale -// Description: Hold localized text used in dates -//=================================================== -class DateLocale { - - public $iLocale = 'C'; // environmental locale be used by default - private $iDayAbb = null, $iShortDay = null, $iShortMonth = null, $iMonthName = null; - - function __construct() { - settype($this->iDayAbb, 'array'); - settype($this->iShortDay, 'array'); - settype($this->iShortMonth, 'array'); - settype($this->iMonthName, 'array'); - $this->Set('C'); - } - - function Set($aLocale) { - if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ - $this->iLocale = $aLocale; - return TRUE; // already cached nothing else to do! - } - - $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME - - if (is_array($aLocale)) { - foreach ($aLocale as $loc) { - $res = @setlocale(LC_TIME, $loc); - if ( $res ) { - $aLocale = $loc; - break; - } - } - } - else { - $res = @setlocale(LC_TIME, $aLocale); - } - - if ( ! $res ) { - JpGraphError::RaiseL(25007,$aLocale); - //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region."); - return FALSE; - } - - $this->iLocale = $aLocale; - for( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ) { - $day = strftime('%a', strtotime("$ofs day")); - $day[0] = strtoupper($day[0]); - $this->iDayAbb[$aLocale][]= $day[0]; - $this->iShortDay[$aLocale][]= $day; - } - - for($i=1; $i<=12; ++$i) { - list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01"))); - $this->iShortMonth[$aLocale][] = ucfirst($short); - $this->iMonthName [$aLocale][] = ucfirst($full); - } - - setlocale(LC_TIME, $pLocale); - - return TRUE; - } - - - function GetDayAbb() { - return $this->iDayAbb[$this->iLocale]; - } - - function GetShortDay() { - return $this->iShortDay[$this->iLocale]; - } - - function GetShortMonth() { - return $this->iShortMonth[$this->iLocale]; - } - - function GetShortMonthName($aNbr) { - return $this->iShortMonth[$this->iLocale][$aNbr]; - } - - function GetLongMonthName($aNbr) { - return $this->iMonthName[$this->iLocale][$aNbr]; - } - - function GetMonth() { - return $this->iMonthName[$this->iLocale]; - } -} - -// Global object handlers -$gDateLocale = new DateLocale(); -$gJpgDateLocale = new DateLocale(); - -//======================================================= -// CLASS Footer -// Description: Encapsulates the footer line in the Graph -//======================================================= -class Footer { - public $iLeftMargin = 3, $iRightMargin = 3, $iBottomMargin = 3 ; - public $left,$center,$right; - private $iTimer=null, $itimerpoststring=''; - - function __construct() { - $this->left = new Text(); - $this->left->ParagraphAlign('left'); - $this->center = new Text(); - $this->center->ParagraphAlign('center'); - $this->right = new Text(); - $this->right->ParagraphAlign('right'); - } - - function SetTimer($aTimer,$aTimerPostString='') { - $this->iTimer = $aTimer; - $this->itimerpoststring = $aTimerPostString; - } - - function SetMargin($aLeft=3,$aRight=3,$aBottom=3) { - $this->iLeftMargin = $aLeft; - $this->iRightMargin = $aRight; - $this->iBottomMargin = $aBottom; - } - - function Stroke($aImg) { - $y = $aImg->height - $this->iBottomMargin; - $x = $this->iLeftMargin; - $this->left->Align('left','bottom'); - $this->left->Stroke($aImg,$x,$y); - - $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2; - $this->center->Align('center','bottom'); - $this->center->Stroke($aImg,$x,$y); - - $x = $aImg->width - $this->iRightMargin; - $this->right->Align('right','bottom'); - if( $this->iTimer != null ) { - $this->right->Set( $this->right->t . sprintf('%.3f',$this->iTimer->Pop()/1000.0) . $this->itimerpoststring ); - } - $this->right->Stroke($aImg,$x,$y); - } -} - - -//=================================================== -// CLASS Graph -// Description: Main class to handle graphs -//=================================================== -class Graph { - public $cache=null; // Cache object (singleton) - public $img=null; // Img object (singleton) - public $plots=array(); // Array of all plot object in the graph (for Y 1 axis) - public $y2plots=array(); // Array of all plot object in the graph (for Y 2 axis) - public $ynplots=array(); - public $xscale=null; // X Scale object (could be instance of LinearScale or LogScale - public $yscale=null,$y2scale=null, $ynscale=array(); - public $iIcons = array(); // Array of Icons to add to - public $cache_name; // File name to be used for the current graph in the cache directory - public $xgrid=null; // X Grid object (linear or logarithmic) - public $ygrid=null,$y2grid=null; //dito for Y - public $doframe=true,$frame_color='black', $frame_weight=1; // Frame around graph - public $boxed=false, $box_color='black', $box_weight=1; // Box around plot area - public $doshadow=false,$shadow_width=4,$shadow_color='gray@0.5'; // Shadow for graph - public $xaxis=null; // X-axis (instane of Axis class) - public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class) - public $margin_color=array(230,230,230); // Margin color of graph - public $plotarea_color=array(255,255,255); // Plot area color - public $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object - public $axtype="linlin"; // Type of axis - public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width - public $texts=null, $y2texts=null; // Text object to ge shown in the graph - public $lines=null, $y2lines=null; - public $bands=null, $y2bands=null; - public $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale in fractions and for centering bars - public $background_image='',$background_image_type=-1,$background_image_format="png"; - public $background_image_bright=0,$background_image_contr=0,$background_image_sat=0; - public $background_image_xpos=0,$background_image_ypos=0; - public $image_bright=0, $image_contr=0, $image_sat=0; - public $inline; - public $showcsim=0,$csimcolor="red";//debug stuff, draw the csim boundaris on the image if <>0 - public $grid_depth=DEPTH_BACK; // Draw grid under all plots as default - public $iAxisStyle = AXSTYLE_SIMPLE; - public $iCSIMdisplay=false,$iHasStroked = false; - public $footer; - public $csimcachename = '', $csimcachetimeout = 0, $iCSIMImgAlt=''; - public $iDoClipping = false; - public $y2orderback=true; - public $tabtitle; - public $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN; - public $bkg_gradfrom='navy', $bkg_gradto='silver'; - public $plot_gradtype=-1,$plot_gradstyle=BGRAD_MARGIN; - public $plot_gradfrom='silver', $plot_gradto='navy'; - - public $titlebackground = false; - public $titlebackground_color = 'lightblue', - $titlebackground_style = 1, - $titlebackground_framecolor = 'blue', - $titlebackground_framestyle = 2, - $titlebackground_frameweight = 1, - $titlebackground_bevelheight = 3 ; - public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; - public $titlebkg_scolor1='black',$titlebkg_scolor2='white'; - public $framebevel = false, $framebeveldepth = 2 ; - public $framebevelborder = false, $framebevelbordercolor='black'; - public $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4'; - public $background_image_mix=100; - public $background_cflag = ''; - public $background_cflag_type = BGIMG_FILLPLOT; - public $background_cflag_mix = 100; - public $iImgTrans=false, - $iImgTransHorizon = 100,$iImgTransSkewDist=150, - $iImgTransDirection = 1, $iImgTransMinSize = true, - $iImgTransFillColor='white',$iImgTransHighQ=false, - $iImgTransBorder=false,$iImgTransHorizonPos=0.5; - public $legend; - protected $iYAxisDeltaPos=50; - protected $iIconDepth=DEPTH_BACK; - protected $iAxisLblBgType = 0, - $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black', - $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black'; - protected $iTables=NULL; - - // aWIdth Width in pixels of image - // aHeight Height in pixels of image - // aCachedName Name for image file in cache directory - // aTimeOut Timeout in minutes for image in cache - // aInline If true the image is streamed back in the call to Stroke() - // If false the image is just created in the cache - function __construct($aWidth=300,$aHeight=200,$aCachedName='',$aTimeout=0,$aInline=true) { - - if( !is_numeric($aWidth) || !is_numeric($aHeight) ) { - JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); - } - - // Automatically generate the image file name based on the name of the script that - // generates the graph - if( $aCachedName == 'auto' ) { - $aCachedName=GenImgName(); - } - - // Should the image be streamed back to the browser or only to the cache? - $this->inline=$aInline; - - $this->img = new RotImage($aWidth,$aHeight); - $this->cache = new ImgStreamCache(); - - // Window doesn't like '?' in the file name so replace it with an '_' - $aCachedName = str_replace("?","_",$aCachedName); - $this->SetupCache($aCachedName, $aTimeout); - - $this->title = new Text(); - $this->title->ParagraphAlign('center'); - $this->title->SetFont(FF_FONT2,FS_BOLD); - $this->title->SetMargin(5); - $this->title->SetAlign('center'); - - $this->subtitle = new Text(); - $this->subtitle->ParagraphAlign('center'); - $this->subtitle->SetMargin(3); - $this->subtitle->SetAlign('center'); - - $this->subsubtitle = new Text(); - $this->subsubtitle->ParagraphAlign('center'); - $this->subsubtitle->SetMargin(3); - $this->subsubtitle->SetAlign('center'); - - $this->legend = new Legend(); - $this->footer = new Footer(); - - // If the cached version exist just read it directly from the - // cache, stream it back to browser and exit - if( $aCachedName!='' && READ_CACHE && $aInline ) { - if( $this->cache->GetAndStream($this->img,$aCachedName) ) { - exit(); - } - } - - $this->SetTickDensity(); // Normal density - - $this->tabtitle = new GraphTabTitle(); - } - - function SetupCache($aFilename,$aTimeout=60) { - $this->cache_name = $aFilename; - $this->cache->SetTimeOut($aTimeout); - } - - // Enable final image perspective transformation - function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) { - $this->iImgTrans = true; - $this->iImgTransHorizon = $aHorizon; - $this->iImgTransSkewDist= $aSkewDist; - $this->iImgTransDirection = $aDir; - $this->iImgTransMinSize = $aMinSize; - $this->iImgTransFillColor=$aFillColor; - $this->iImgTransHighQ=$aQuality; - $this->iImgTransBorder=$aBorder; - $this->iImgTransHorizonPos=$aHorizonPos; - } - - function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->img->ttf->SetUserFont($aNormal,$aBold,$aItalic,$aBoldIt); - } - - function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->img->ttf->SetUserFont1($aNormal,$aBold,$aItalic,$aBoldIt); - } - - function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->img->ttf->SetUserFont2($aNormal,$aBold,$aItalic,$aBoldIt); - } - - function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->img->ttf->SetUserFont3($aNormal,$aBold,$aItalic,$aBoldIt); - } - - // Set Image format and optional quality - function SetImgFormat($aFormat,$aQuality=75) { - $this->img->SetImgFormat($aFormat,$aQuality); - } - - // Should the grid be in front or back of the plot? - function SetGridDepth($aDepth) { - $this->grid_depth=$aDepth; - } - - function SetIconDepth($aDepth) { - $this->iIconDepth=$aDepth; - } - - // Specify graph angle 0-360 degrees. - function SetAngle($aAngle) { - $this->img->SetAngle($aAngle); - } - - function SetAlphaBlending($aFlg=true) { - $this->img->SetAlphaBlending($aFlg); - } - - // Shortcut to image margin - function SetMargin($lm,$rm,$tm,$bm) { - $this->img->SetMargin($lm,$rm,$tm,$bm); - } - - function SetY2OrderBack($aBack=true) { - $this->y2orderback = $aBack; - } - - // Rotate the graph 90 degrees and set the margin - // when we have done a 90 degree rotation - function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { - $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ; - $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ; - $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ; - $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ; - - $adj = ($this->img->height - $this->img->width)/2; - $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj); - $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); - $this->SetAngle(90); - if( empty($this->yaxis) || empty($this->xaxis) ) { - JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()'); - } - $this->xaxis->SetLabelAlign('right','center'); - $this->yaxis->SetLabelAlign('center','bottom'); - } - - function SetClipping($aFlg=true) { - $this->iDoClipping = $aFlg ; - } - - // Add a plot object to the graph - function Add($aPlot) { - if( $aPlot == null ) { - JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); - } - if( is_array($aPlot) && count($aPlot) > 0 ) { - $cl = $aPlot[0]; - } - else { - $cl = $aPlot; - } - - if( $cl instanceof Text ) $this->AddText($aPlot); - elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) $this->AddLine($aPlot); - elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) $this->AddBand($aPlot); - elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot); - elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) $this->AddTable($aPlot); - else { - if( is_array($aPlot) ) { - $this->plots = array_merge($this->plots,$aPlot); - } - else { - $this->plots[] = $aPlot; - } - } - } - - function AddTable($aTable) { - if( is_array($aTable) ) { - for($i=0; $i < count($aTable); ++$i ) { - $this->iTables[]=$aTable[$i]; - } - } - else { - $this->iTables[] = $aTable ; - } - } - - function AddIcon($aIcon) { - if( is_array($aIcon) ) { - for($i=0; $i < count($aIcon); ++$i ) { - $this->iIcons[]=$aIcon[$i]; - } - } - else { - $this->iIcons[] = $aIcon ; - } - } - - // Add plot to second Y-scale - function AddY2($aPlot) { - if( $aPlot == null ) { - JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph."); - } - - if( is_array($aPlot) && count($aPlot) > 0 ) { - $cl = $aPlot[0]; - } - else { - $cl = $aPlot; - } - - if( $cl instanceof Text ) { - $this->AddText($aPlot,true); - } - elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) { - $this->AddLine($aPlot,true); - } - elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) { - $this->AddBand($aPlot,true); - } - else { - $this->y2plots[] = $aPlot; - } - } - - // Add plot to the extra Y-axises - function AddY($aN,$aPlot) { - - if( $aPlot == null ) { - JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph."); - } - - if( is_array($aPlot) && count($aPlot) > 0 ) { - $cl = $aPlot[0]; - } - else { - $cl = $aPlot; - } - - if( ($cl instanceof Text) || - (class_exists('PlotLine',false) && ($cl instanceof PlotLine)) || - (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) { - JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis'); - } - else { - $this->ynplots[$aN][] = $aPlot; - } - } - - // Add text object to the graph - function AddText($aTxt,$aToY2=false) { - if( $aTxt == null ) { - JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph."); - } - if( $aToY2 ) { - if( is_array($aTxt) ) { - for($i=0; $i < count($aTxt); ++$i ) { - $this->y2texts[]=$aTxt[$i]; - } - } - else { - $this->y2texts[] = $aTxt; - } - } - else { - if( is_array($aTxt) ) { - for($i=0; $i < count($aTxt); ++$i ) { - $this->texts[]=$aTxt[$i]; - } - } - else { - $this->texts[] = $aTxt; - } - } - } - - // Add a line object (class PlotLine) to the graph - function AddLine($aLine,$aToY2=false) { - if( $aLine == null ) { - JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph."); - } - - if( $aToY2 ) { - if( is_array($aLine) ) { - for($i=0; $i < count($aLine); ++$i ) { - //$this->y2lines[]=$aLine[$i]; - $this->y2plots[]=$aLine[$i]; - } - } - else { - //$this->y2lines[] = $aLine; - $this->y2plots[]=$aLine; - } - } - else { - if( is_array($aLine) ) { - for($i=0; $ilines[]=$aLine[$i]; - $this->plots[]=$aLine[$i]; - } - } - else { - //$this->lines[] = $aLine; - $this->plots[] = $aLine; - } - } - } - - // Add vertical or horizontal band - function AddBand($aBand,$aToY2=false) { - if( $aBand == null ) { - JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph."); - } - - if( $aToY2 ) { - if( is_array($aBand) ) { - for($i=0; $i < count($aBand); ++$i ) { - $this->y2bands[] = $aBand[$i]; - } - } - else { - $this->y2bands[] = $aBand; - } - } - else { - if( is_array($aBand) ) { - for($i=0; $i < count($aBand); ++$i ) { - $this->bands[] = $aBand[$i]; - } - } - else { - $this->bands[] = $aBand; - } - } - } - - function SetPlotGradient($aFrom='navy',$aTo='silver',$aGradType=2) { - $this->plot_gradtype=$aGradType; - $this->plot_gradfrom = $aFrom; - $this->plot_gradto = $aTo; - } - - function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) { - $this->bkg_gradtype=$aGradType; - $this->bkg_gradstyle=$aStyle; - $this->bkg_gradfrom = $aFrom; - $this->bkg_gradto = $aTo; - } - - // Set a country flag in the background - function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { - $this->background_cflag = $aName; - $this->background_cflag_type = $aBgType; - $this->background_cflag_mix = $aMix; - } - - // Alias for the above method - function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { - $this->background_cflag = $aName; - $this->background_cflag_type = $aBgType; - $this->background_cflag_mix = $aMix; - } - - - // Specify a background image - function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat='auto') { - - // Get extension to determine image type - if( $aImgFormat == 'auto' ) { - $e = explode('.',$aFileName); - if( !$e ) { - JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); - } - - $valid_formats = array('png', 'jpg', 'gif'); - $aImgFormat = strtolower($e[count($e)-1]); - if ($aImgFormat == 'jpeg') { - $aImgFormat = 'jpg'; - } - elseif (!in_array($aImgFormat, $valid_formats) ) { - JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName); - } - } - - $this->background_image = $aFileName; - $this->background_image_type=$aBgType; - $this->background_image_format=$aImgFormat; - } - - function SetBackgroundImageMix($aMix) { - $this->background_image_mix = $aMix ; - } - - // Adjust background image position - function SetBackgroundImagePos($aXpos,$aYpos) { - $this->background_image_xpos = $aXpos ; - $this->background_image_ypos = $aYpos ; - } - - // Specify axis style (boxed or single) - function SetAxisStyle($aStyle) { - $this->iAxisStyle = $aStyle ; - } - - // Set a frame around the plot area - function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) { - $this->boxed = $aDrawPlotFrame; - $this->box_weight = $aPlotFrameWeight; - $this->box_color = $aPlotFrameColor; - } - - // Specify color for the plotarea (not the margins) - function SetColor($aColor) { - $this->plotarea_color=$aColor; - } - - // Specify color for the margins (all areas outside the plotarea) - function SetMarginColor($aColor) { - $this->margin_color=$aColor; - } - - // Set a frame around the entire image - function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) { - $this->doframe = $aDrawImgFrame; - $this->frame_color = $aImgFrameColor; - $this->frame_weight = $aImgFrameWeight; - } - - function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) { - $this->framebevel = $aFlg ; - $this->framebeveldepth = $aDepth ; - $this->framebevelborder = $aBorder ; - $this->framebevelbordercolor = $aBorderColor ; - $this->framebevelcolor1 = $aColor1 ; - $this->framebevelcolor2 = $aColor2 ; - - $this->doshadow = false ; - } - - // Set the shadow around the whole image - function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor='darkgray') { - $this->doshadow = $aShowShadow; - $this->shadow_color = $aShadowColor; - $this->shadow_width = $aShadowWidth; - $this->footer->iBottomMargin += $aShadowWidth; - $this->footer->iRightMargin += $aShadowWidth; - } - - // Specify x,y scale. Note that if you manually specify the scale - // you must also specify the tick distance with a call to Ticks::Set() - function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { - $this->axtype = $aAxisType; - - if( $aYMax < $aYMin || $aXMax < $aXMin ) { - JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.'); - } - - $yt=substr($aAxisType,-3,3); - if( $yt == 'lin' ) { - $this->yscale = new LinearScale($aYMin,$aYMax); - } - elseif( $yt == 'int' ) { - $this->yscale = new LinearScale($aYMin,$aYMax); - $this->yscale->SetIntScale(); - } - elseif( $yt == 'log' ) { - $this->yscale = new LogScale($aYMin,$aYMax); - } - else { - JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)"); - } - - $xt=substr($aAxisType,0,3); - if( $xt == 'lin' || $xt == 'tex' ) { - $this->xscale = new LinearScale($aXMin,$aXMax,'x'); - $this->xscale->textscale = ($xt == 'tex'); - } - elseif( $xt == 'int' ) { - $this->xscale = new LinearScale($aXMin,$aXMax,'x'); - $this->xscale->SetIntScale(); - } - elseif( $xt == 'dat' ) { - $this->xscale = new DateScale($aXMin,$aXMax,'x'); - } - elseif( $xt == 'log' ) { - $this->xscale = new LogScale($aXMin,$aXMax,'x'); - } - else { - JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)"); - } - - $this->xaxis = new Axis($this->img,$this->xscale); - $this->yaxis = new Axis($this->img,$this->yscale); - $this->xgrid = new Grid($this->xaxis); - $this->ygrid = new Grid($this->yaxis); - $this->ygrid->Show(); - } - - // Specify secondary Y scale - function SetY2Scale($aAxisType='lin',$aY2Min=1,$aY2Max=1) { - if( $aAxisType == 'lin' ) { - $this->y2scale = new LinearScale($aY2Min,$aY2Max); - } - elseif( $aAxisType == 'int' ) { - $this->y2scale = new LinearScale($aY2Min,$aY2Max); - $this->y2scale->SetIntScale(); - } - elseif( $aAxisType == 'log' ) { - $this->y2scale = new LogScale($aY2Min,$aY2Max); - } - else { - JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)"); - } - - $this->y2axis = new Axis($this->img,$this->y2scale); - $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); - $this->y2axis->SetLabelSide(SIDE_RIGHT); - $this->y2axis->SetPos('max'); - $this->y2axis->SetTitleSide(SIDE_RIGHT); - - // Deafult position is the max x-value - $this->y2grid = new Grid($this->y2axis); - } - - // Set the delta position (in pixels) between the multiple Y-axis - function SetYDeltaDist($aDist) { - $this->iYAxisDeltaPos = $aDist; - } - - // Specify secondary Y scale - function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) { - - if( $aAxisType == 'lin' ) { - $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); - } - elseif( $aAxisType == 'int' ) { - $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); - $this->ynscale[$aN]->SetIntScale(); - } - elseif( $aAxisType == 'log' ) { - $this->ynscale[$aN] = new LogScale($aYMin,$aYMax); - } - else { - JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)"); - } - - $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); - $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); - $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); - } - - // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' - // The dividing factor have been determined heuristically according to my aesthetic - // sense (or lack off) y.m.m.v ! - function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) { - $this->xtick_factor=30; - $this->ytick_factor=25; - switch( $aYDensity ) { - case TICKD_DENSE: - $this->ytick_factor=12; - break; - case TICKD_NORMAL: - $this->ytick_factor=25; - break; - case TICKD_SPARSE: - $this->ytick_factor=40; - break; - case TICKD_VERYSPARSE: - $this->ytick_factor=100; - break; - default: - JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy"); - } - switch( $aXDensity ) { - case TICKD_DENSE: - $this->xtick_factor=15; - break; - case TICKD_NORMAL: - $this->xtick_factor=30; - break; - case TICKD_SPARSE: - $this->xtick_factor=45; - break; - case TICKD_VERYSPARSE: - $this->xtick_factor=60; - break; - default: - JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx"); - } - } - - - // Get a string of all image map areas - function GetCSIMareas() { - if( !$this->iHasStroked ) { - $this->Stroke(_CSIM_SPECIALFILE); - } - - $csim = $this->title->GetCSIMAreas(); - $csim .= $this->subtitle->GetCSIMAreas(); - $csim .= $this->subsubtitle->GetCSIMAreas(); - $csim .= $this->legend->GetCSIMAreas(); - - if( $this->y2axis != NULL ) { - $csim .= $this->y2axis->title->GetCSIMAreas(); - } - - if( $this->texts != null ) { - $n = count($this->texts); - for($i=0; $i < $n; ++$i ) { - $csim .= $this->texts[$i]->GetCSIMAreas(); - } - } - - if( $this->y2texts != null && $this->y2scale != null ) { - $n = count($this->y2texts); - for($i=0; $i < $n; ++$i ) { - $csim .= $this->y2texts[$i]->GetCSIMAreas(); - } - } - - if( $this->yaxis != null && $this->xaxis != null ) { - $csim .= $this->yaxis->title->GetCSIMAreas(); - $csim .= $this->xaxis->title->GetCSIMAreas(); - } - - $n = count($this->plots); - for( $i=0; $i < $n; ++$i ) { - $csim .= $this->plots[$i]->GetCSIMareas(); - } - - $n = count($this->y2plots); - for( $i=0; $i < $n; ++$i ) { - $csim .= $this->y2plots[$i]->GetCSIMareas(); - } - - $n = count($this->ynaxis); - for( $i=0; $i < $n; ++$i ) { - $m = count($this->ynplots[$i]); - for($j=0; $j < $m; ++$j ) { - $csim .= $this->ynplots[$i][$j]->GetCSIMareas(); - } - } - - $n = count($this->iTables); - for( $i=0; $i < $n; ++$i ) { - $csim .= $this->iTables[$i]->GetCSIMareas(); - } - - return $csim; - } - - // Get a complete .. tag for the final image map - function GetHTMLImageMap($aMapName) { - $im = "\n"; - $im .= $this->GetCSIMareas(); - $im .= ""; - return $im; - } - - function CheckCSIMCache($aCacheName,$aTimeOut=60) { - global $_SERVER; - - if( $aCacheName=='auto' ) { - $aCacheName=basename($_SERVER['PHP_SELF']); - } - - $urlarg = $this->GetURLArguments(); - $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg; - $this->csimcachetimeout = $aTimeOut; - - // First determine if we need to check for a cached version - // This differs from the standard cache in the sense that the - // image and CSIM map HTML file is written relative to the directory - // the script executes in and not the specified cache directory. - // The reason for this is that the cache directory is not necessarily - // accessible from the HTTP server. - if( $this->csimcachename != '' ) { - $dir = dirname($this->csimcachename); - $base = basename($this->csimcachename); - $base = strtok($base,'.'); - $suffix = strtok('.'); - $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; - $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format; - - $timedout=false; - // Does it exist at all ? - - if( file_exists($basecsim) && file_exists($baseimg) ) { - // Check that it hasn't timed out - $diff=time()-filemtime($basecsim); - if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) { - $timedout=true; - @unlink($basecsim); - @unlink($baseimg); - } - else { - if ($fh = @fopen($basecsim, "r")) { - fpassthru($fh); - return true; - } - else { - JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading."); - } - } - } - } - return false; - } - - // Build the argument string to be used with the csim images - static function GetURLArguments($aAddRecursiveBlocker=false) { - - if( $aAddRecursiveBlocker ) { - // This is a JPGRAPH internal defined that prevents - // us from recursively coming here again - $urlarg = _CSIM_DISPLAY.'=1'; - } - - // Now reconstruct any user URL argument - reset($_GET); - while( list($key,$value) = each($_GET) ) { - if( is_array($value) ) { - foreach ( $value as $k => $v ) { - $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); - } - } - else { - $urlarg .= '&'.$key.'='.urlencode($value); - } - } - - // It's not ideal to convert POST argument to GET arguments - // but there is little else we can do. One idea for the - // future might be recreate the POST header in case. - reset($_POST); - while( list($key,$value) = each($_POST) ) { - if( is_array($value) ) { - foreach ( $value as $k => $v ) { - $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); - } - } - else { - $urlarg .= '&'.$key.'='.urlencode($value); - } - } - - return $urlarg; - } - - function SetCSIMImgAlt($aAlt) { - $this->iCSIMImgAlt = $aAlt; - } - - function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) { - if( $aCSIMName=='' ) { - // create a random map name - srand ((double) microtime() * 1000000); - $r = rand(0,100000); - $aCSIMName='__mapname'.$r.'__'; - } - - if( $aScriptName=='auto' ) { - $aScriptName=basename($_SERVER['PHP_SELF']); - } - - $urlarg = $this->GetURLArguments(true); - - if( empty($_GET[_CSIM_DISPLAY]) ) { - // First determine if we need to check for a cached version - // This differs from the standard cache in the sense that the - // image and CSIM map HTML file is written relative to the directory - // the script executes in and not the specified cache directory. - // The reason for this is that the cache directory is not necessarily - // accessible from the HTTP server. - if( $this->csimcachename != '' ) { - $dir = dirname($this->csimcachename); - $base = basename($this->csimcachename); - $base = strtok($base,'.'); - $suffix = strtok('.'); - $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; - $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format; - - // Check that apache can write to directory specified - - if( file_exists($dir) && !is_writeable($dir) ) { - JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.'); - } - - // Make sure directory exists - $this->cache->MakeDirs($dir); - - // Write the image file - $this->Stroke(CSIMCACHE_DIR.$baseimg); - - // Construct wrapper HTML and write to file and send it back to browser - - // In the src URL we must replace the '?' with its encoding to prevent the arguments - // to be converted to real arguments. - $tmp = str_replace('?','%3f',$baseimg); - $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n". - 'img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n"; - - if($fh = @fopen($basecsim,'w') ) { - fwrite($fh,$htmlwrap); - fclose($fh); - echo $htmlwrap; - } - else { - JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions."); - } - } - else { - - if( $aScriptName=='' ) { - JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().'); - } - echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder); - } - } - else { - $this->Stroke(); - } - } - - function StrokeCSIMImage() { - if( @$_GET[_CSIM_DISPLAY] == 1 ) { - $this->Stroke(); - } - } - - function GetCSIMImgHTML($aCSIMName, $aScriptName='auto', $aBorder=0 ) { - if( $aScriptName=='auto' ) { - $aScriptName=basename($_SERVER['PHP_SELF']); - } - $urlarg = $this->GetURLArguments(true); - return "\"".$this-iCSIMImgAlt."\" />\n"; - } - - function GetTextsYMinMax($aY2=false) { - if( $aY2 ) { - $txts = $this->y2texts; - } - else { - $txts = $this->texts; - } - $n = count($txts); - $min=null; - $max=null; - for( $i=0; $i < $n; ++$i ) { - if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) { - if( $min === null ) { - $min = $max = $txts[$i]->iScalePosY ; - } - else { - $min = min($min,$txts[$i]->iScalePosY); - $max = max($max,$txts[$i]->iScalePosY); - } - } - } - if( $min !== null ) { - return array($min,$max); - } - else { - return null; - } - } - - function GetTextsXMinMax($aY2=false) { - if( $aY2 ) { - $txts = $this->y2texts; - } - else { - $txts = $this->texts; - } - $n = count($txts); - $min=null; - $max=null; - for( $i=0; $i < $n; ++$i ) { - if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) { - if( $min === null ) { - $min = $max = $txts[$i]->iScalePosX ; - } - else { - $min = min($min,$txts[$i]->iScalePosX); - $max = max($max,$txts[$i]->iScalePosX); - } - } - } - if( $min !== null ) { - return array($min,$max); - } - else { - return null; - } - } - - function GetXMinMax() { - - list($min,$ymin) = $this->plots[0]->Min(); - list($max,$ymax) = $this->plots[0]->Max(); - - $i=0; - // Some plots, e.g. PlotLine should not affect the scale - // and will return (null,null). We should ignore those - // values. - while( ($min===null || $max === null) && ($i < count($this->plots)-1) ) { - ++$i; - list($min,$ymin) = $this->plots[$i]->Min(); - list($max,$ymax) = $this->plots[$i]->Max(); - } - - foreach( $this->plots as $p ) { - list($xmin,$ymin) = $p->Min(); - list($xmax,$ymax) = $p->Max(); - - if( $xmin !== null && $xmax !== null ) { - $min = Min($xmin,$min); - $max = Max($xmax,$max); - } - } - - if( $this->y2axis != null ) { - foreach( $this->y2plots as $p ) { - list($xmin,$ymin) = $p->Min(); - list($xmax,$ymax) = $p->Max(); - $min = Min($xmin,$min); - $max = Max($xmax,$max); - } - } - - $n = count($this->ynaxis); - for( $i=0; $i < $n; ++$i ) { - if( $this->ynaxis[$i] != null) { - foreach( $this->ynplots[$i] as $p ) { - list($xmin,$ymin) = $p->Min(); - list($xmax,$ymax) = $p->Max(); - $min = Min($xmin,$min); - $max = Max($xmax,$max); - } - } - } - return array($min,$max); - } - - function AdjustMarginsForTitles() { - $totrequired = ($this->title->t != '' ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) + - ($this->subtitle->t != '' ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + - ($this->subsubtitle->t != '' ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ; - - $btotrequired = 0; - if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { - // Minimum bottom margin - if( $this->xaxis->title->t != '' ) { - if( $this->img->a == 90 ) { - $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7 ; - } - else { - $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7 ; - } - } - else { - $btotrequired = 0; - } - - if( $this->img->a == 90 ) { - $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style, - $this->yaxis->font_size); - $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle); - } - else { - $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style, - $this->xaxis->font_size); - $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle); - } - - $btotrequired += $lh + 6; - } - - if( $this->img->a == 90 ) { - // DO Nothing. It gets too messy to do this properly for 90 deg... - } - else{ - if( $this->img->top_margin < $totrequired ) { - $this->SetMargin($this->img->left_margin,$this->img->right_margin, - $totrequired,$this->img->bottom_margin); - } - if( $this->img->bottom_margin < $btotrequired ) { - $this->SetMargin($this->img->left_margin,$this->img->right_margin, - $this->img->top_margin,$btotrequired); - } - } - } - - function StrokeStore($aStrokeFileName) { - // Get the handler to prevent the library from sending the - // image to the browser - $ih = $this->Stroke(_IMG_HANDLER); - - // Stroke it to a file - $this->img->Stream($aStrokeFileName); - - // Send it back to browser - $this->img->Headers(); - $this->img->Stream(); - } - - function doAutoscaleXAxis() { - //Check if we should autoscale x-axis - if( !$this->xscale->IsSpecified() ) { - if( substr($this->axtype,0,4) == "text" ) { - $max=0; - $n = count($this->plots); - for($i=0; $i < $n; ++$i ) { - $p = $this->plots[$i]; - // We need some unfortunate sub class knowledge here in order - // to increase number of data points in case it is a line plot - // which has the barcenter set. If not it could mean that the - // last point of the data is outside the scale since the barcenter - // settings means that we will shift the entire plot half a tick step - // to the right in oder to align with the center of the bars. - if( class_exists('BarPlot',false) ) { - $cl = strtolower(get_class($p)); - if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || empty($p->barcenter) ) { - $max=max($max,$p->numpoints-1); - } - else { - $max=max($max,$p->numpoints); - } - } - else { - if( empty($p->barcenter) ) { - $max=max($max,$p->numpoints-1); - } - else { - $max=max($max,$p->numpoints); - } - } - } - $min=0; - if( $this->y2axis != null ) { - foreach( $this->y2plots as $p ) { - $max=max($max,$p->numpoints-1); - } - } - $n = count($this->ynaxis); - for( $i=0; $i < $n; ++$i ) { - if( $this->ynaxis[$i] != null) { - foreach( $this->ynplots[$i] as $p ) { - $max=max($max,$p->numpoints-1); - } - } - } - - $this->xscale->Update($this->img,$min,$max); - $this->xscale->ticks->Set($this->xaxis->tick_step,1); - $this->xscale->ticks->SupressMinorTickMarks(); - } - else { - list($min,$max) = $this->GetXMinMax(); - - $lres = $this->GetLinesXMinMax($this->lines); - if( $lres ) { - list($linmin,$linmax) = $lres ; - $min = min($min,$linmin); - $max = max($max,$linmax); - } - - $lres = $this->GetLinesXMinMax($this->y2lines); - if( $lres ) { - list($linmin,$linmax) = $lres ; - $min = min($min,$linmin); - $max = max($max,$linmax); - } - - $tres = $this->GetTextsXMinMax(); - if( $tres ) { - list($tmin,$tmax) = $tres ; - $min = min($min,$tmin); - $max = max($max,$tmax); - } - - $tres = $this->GetTextsXMinMax(true); - if( $tres ) { - list($tmin,$tmax) = $tres ; - $min = min($min,$tmin); - $max = max($max,$tmax); - } - - $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor)); - } - - //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale - if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) { - $this->yaxis->SetPos($this->xscale->GetMinVal()); - } - } - elseif( $this->xscale->IsSpecified() && - ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) { - // The tick calculation will use the user suplied min/max values to determine - // the ticks. If auto_ticks is false the exact user specifed min and max - // values will be used for the scale. - // If auto_ticks is true then the scale might be slightly adjusted - // so that the min and max values falls on an even major step. - $min = $this->xscale->scale[0]; - $max = $this->xscale->scale[1]; - $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor),false); - - // Now make sure we show enough precision to accurate display the - // labels. If this is not done then the user might end up with - // a scale that might actually start with, say 13.5, butdue to rounding - // the scale label will ony show 14. - if( abs(floor($min)-$min) > 0 ) { - - // If the user has set a format then we bail out - if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) { - $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; - } - } - } - - // Position the optional Y2 and Yn axis to the rightmost position of the x-axis - if( $this->y2axis != null ) { - if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) { - $this->y2axis->SetPos($this->xscale->GetMaxVal()); - } - $this->y2axis->SetTitleSide(SIDE_RIGHT); - } - - $n = count($this->ynaxis); - $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0; - for( $i=0; $i < $n; ++$i ) { - if( $this->ynaxis[$i] != null ) { - if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) { - $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal()); - $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj); - } - $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT); - } - } - } - - - function doAutoScaleYnAxis() { - - if( $this->y2scale != null) { - if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { - list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); - - $lres = $this->GetLinesYMinMax($this->y2lines); - if( is_array($lres) ) { - list($linmin,$linmax) = $lres ; - $min = min($min,$linmin); - $max = max($max,$linmax); - } - $tres = $this->GetTextsYMinMax(true); - if( is_array($tres) ) { - list($tmin,$tmax) = $tres ; - $min = min($min,$tmin); - $max = max($max,$tmax); - } - $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); - } - elseif( $this->y2scale->IsSpecified() && ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) { - // The tick calculation will use the user suplied min/max values to determine - // the ticks. If auto_ticks is false the exact user specifed min and max - // values will be used for the scale. - // If auto_ticks is true then the scale might be slightly adjusted - // so that the min and max values falls on an even major step. - $min = $this->y2scale->scale[0]; - $max = $this->y2scale->scale[1]; - $this->y2scale->AutoScale($this->img,$min,$max, - $this->img->plotheight/$this->ytick_factor, - $this->y2scale->auto_ticks); - - // Now make sure we show enough precision to accurate display the - // labels. If this is not done then the user might end up with - // a scale that might actually start with, say 13.5, butdue to rounding - // the scale label will ony show 14. - if( abs(floor($min)-$min) > 0 ) { - // If the user has set a format then we bail out - if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) { - $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; - } - } - - } - } - - - // - // Autoscale the extra Y-axises - // - $n = count($this->ynaxis); - for( $i=0; $i < $n; ++$i ) { - if( $this->ynscale[$i] != null) { - if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) { - list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]); - $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); - } - elseif( $this->ynscale[$i]->IsSpecified() && ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) { - // The tick calculation will use the user suplied min/max values to determine - // the ticks. If auto_ticks is false the exact user specifed min and max - // values will be used for the scale. - // If auto_ticks is true then the scale might be slightly adjusted - // so that the min and max values falls on an even major step. - $min = $this->ynscale[$i]->scale[0]; - $max = $this->ynscale[$i]->scale[1]; - $this->ynscale[$i]->AutoScale($this->img,$min,$max, - $this->img->plotheight/$this->ytick_factor, - $this->ynscale[$i]->auto_ticks); - - // Now make sure we show enough precision to accurate display the - // labels. If this is not done then the user might end up with - // a scale that might actually start with, say 13.5, butdue to rounding - // the scale label will ony show 14. - if( abs(floor($min)-$min) > 0 ) { - // If the user has set a format then we bail out - if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) { - $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; - } - } - } - } - } - } - - function doAutoScaleYAxis() { - - //Check if we should autoscale y-axis - if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { - list($min,$max) = $this->GetPlotsYMinMax($this->plots); - $lres = $this->GetLinesYMinMax($this->lines); - if( is_array($lres) ) { - list($linmin,$linmax) = $lres ; - $min = min($min,$linmin); - $max = max($max,$linmax); - } - $tres = $this->GetTextsYMinMax(); - if( is_array($tres) ) { - list($tmin,$tmax) = $tres ; - $min = min($min,$tmin); - $max = max($max,$tmax); - } - $this->yscale->AutoScale($this->img,$min,$max, - $this->img->plotheight/$this->ytick_factor); - } - elseif( $this->yscale->IsSpecified() && ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { - // The tick calculation will use the user suplied min/max values to determine - // the ticks. If auto_ticks is false the exact user specifed min and max - // values will be used for the scale. - // If auto_ticks is true then the scale might be slightly adjusted - // so that the min and max values falls on an even major step. - $min = $this->yscale->scale[0]; - $max = $this->yscale->scale[1]; - $this->yscale->AutoScale($this->img,$min,$max, - $this->img->plotheight/$this->ytick_factor, - $this->yscale->auto_ticks); - - // Now make sure we show enough precision to accurate display the - // labels. If this is not done then the user might end up with - // a scale that might actually start with, say 13.5, butdue to rounding - // the scale label will ony show 14. - if( abs(floor($min)-$min) > 0 ) { - - // If the user has set a format then we bail out - if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) { - $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; - } - } - } - - } - - function InitScaleConstants() { - // Setup scale constants - if( $this->yscale ) $this->yscale->InitConstants($this->img); - if( $this->xscale ) $this->xscale->InitConstants($this->img); - if( $this->y2scale ) $this->y2scale->InitConstants($this->img); - - $n=count($this->ynscale); - for($i=0; $i < $n; ++$i) { - if( $this->ynscale[$i] ) { - $this->ynscale[$i]->InitConstants($this->img); - } - } - } - - function doPrestrokeAdjustments() { - - // Do any pre-stroke adjustment that is needed by the different plot types - // (i.e bar plots want's to add an offset to the x-labels etc) - for($i=0; $i < count($this->plots) ; ++$i ) { - $this->plots[$i]->PreStrokeAdjust($this); - $this->plots[$i]->DoLegend($this); - } - - // Any plots on the second Y scale? - if( $this->y2scale != null ) { - for($i=0; $iy2plots) ; ++$i ) { - $this->y2plots[$i]->PreStrokeAdjust($this); - $this->y2plots[$i]->DoLegend($this); - } - } - - // Any plots on the extra Y axises? - $n = count($this->ynaxis); - for($i=0; $i<$n ; ++$i ) { - if( $this->ynplots == null || $this->ynplots[$i] == null) { - JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i"); - } - $m = count($this->ynplots[$i]); - for($j=0; $j < $m; ++$j ) { - $this->ynplots[$i][$j]->PreStrokeAdjust($this); - $this->ynplots[$i][$j]->DoLegend($this); - } - } - } - - function StrokeBands($aDepth,$aCSIM) { - // Stroke bands - if( $this->bands != null && !$aCSIM) { - for($i=0; $i < count($this->bands); ++$i) { - // Stroke all bands that asks to be in the background - if( $this->bands[$i]->depth == $aDepth ) { - $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); - } - } - } - - if( $this->y2bands != null && $this->y2scale != null && !$aCSIM ) { - for($i=0; $i < count($this->y2bands); ++$i) { - // Stroke all bands that asks to be in the foreground - if( $this->y2bands[$i]->depth == $aDepth ) { - $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); - } - } - } - } - - - // Stroke the graph - // $aStrokeFileName If != "" the image will be written to this file and NOT - // streamed back to the browser - function Stroke($aStrokeFileName='') { - - // Fist make a sanity check that user has specified a scale - if( empty($this->yscale) ) { - JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); - } - - // Start by adjusting the margin so that potential titles will fit. - $this->AdjustMarginsForTitles(); - - // Give the plot a chance to do any scale adjuments the individual plots - // wants to do. Right now this is only used by the contour plot to set scale - // limits - for($i=0; $i < count($this->plots) ; ++$i ) { - $this->plots[$i]->PreScaleSetup($this); - } - - // Init scale constants that are used to calculate the transformation from - // world to pixel coordinates - $this->InitScaleConstants(); - - // If the filename is the predefined value = '_csim_special_' - // we assume that the call to stroke only needs to do enough - // to correctly generate the CSIM maps. - // We use this variable to skip things we don't strictly need - // to do to generate the image map to improve performance - // a best we can. Therefor you will see a lot of tests !$_csim in the - // code below. - $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); - - // If we are called the second time (perhaps the user has called GetHTMLImageMap() - // himself then the legends have alsready been populated once in order to get the - // CSIM coordinats. Since we do not want the legends to be populated a second time - // we clear the legends - $this->legend->Clear(); - - // We need to know if we have stroked the plot in the - // GetCSIMareas. Otherwise the CSIM hasn't been generated - // and in the case of GetCSIM called before stroke to generate - // CSIM without storing an image to disk GetCSIM must call Stroke. - $this->iHasStroked = true; - - // Setup pre-stroked adjustments and Legends - $this->doPrestrokeAdjustments(); - - // Bail out if any of the Y-axis not been specified and - // has no plots. (This means it is impossible to do autoscaling and - // no other scale was given so we can't possible draw anything). If you use manual - // scaling you also have to supply the tick steps as well. - if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || - ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { - //$e = "n=".count($this->y2plots)."\n"; - // $e = "Can't draw unspecified Y-scale.
      \nYou have either:
      \n"; - // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots
      \n"; - // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; - JpGraphError::RaiseL(25026); - } - - // Bail out if no plots and no specified X-scale - if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) { - JpGraphError::RaiseL(25034);//("JpGraph: Can't draw unspecified X-scale.
      No plots.
      "); - } - - // Autoscale the normal Y-axis - $this->doAutoScaleYAxis(); - - // Autoscale all additiopnal y-axis - $this->doAutoScaleYnAxis(); - - // Autoscale the regular x-axis and position the y-axis properly - $this->doAutoScaleXAxis(); - - // If we have a negative values and x-axis position is at 0 - // we need to supress the first and possible the last tick since - // they will be drawn on top of the y-axis (and possible y2 axis) - // The test below might seem strange the reasone being that if - // the user hasn't specified a value for position this will not - // be set until we do the stroke for the axis so as of now it - // is undefined. - // For X-text scale we ignore all this since the tick are usually - // much further in and not close to the Y-axis. Hence the test - // for 'text' - if( ($this->yaxis->pos==$this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && - !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && - substr($this->axtype,0,4) != 'text' && $this->xaxis->pos != 'min' ) { - - //$this->yscale->ticks->SupressZeroLabel(false); - $this->xscale->ticks->SupressFirst(); - if( $this->y2axis != null ) { - $this->xscale->ticks->SupressLast(); - } - } - elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) { - $this->xscale->ticks->SupressLast(); - } - - if( !$_csim ) { - $this->StrokePlotArea(); - if( $this->iIconDepth == DEPTH_BACK ) { - $this->StrokeIcons(); - } - } - $this->StrokeAxis(false); - - // Stroke colored bands - $this->StrokeBands(DEPTH_BACK,$_csim); - - if( $this->grid_depth == DEPTH_BACK && !$_csim) { - $this->ygrid->Stroke(); - $this->xgrid->Stroke(); - } - - // Stroke Y2-axis - if( $this->y2axis != null && !$_csim) { - $this->y2axis->Stroke($this->xscale); - $this->y2grid->Stroke(); - } - - // Stroke yn-axis - $n = count($this->ynaxis); - for( $i=0; $i < $n; ++$i ) { - $this->ynaxis[$i]->Stroke($this->xscale); - } - - $oldoff=$this->xscale->off; - if( substr($this->axtype,0,4) == 'text' ) { - if( $this->text_scale_abscenteroff > -1 ) { - // For a text scale the scale factor is the number of pixel per step. - // Hence we can use the scale factor as a substitute for number of pixels - // per major scale step and use that in order to adjust the offset so that - // an object of width "abscenteroff" becomes centered. - $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2); - } - else { - $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); - } - } - - if( $this->iDoClipping ) { - $oldimage = $this->img->CloneCanvasH(); - } - - if( ! $this->y2orderback ) { - // Stroke all plots for Y1 axis - for($i=0; $i < count($this->plots); ++$i) { - $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); - $this->plots[$i]->StrokeMargin($this->img); - } - } - - // Stroke all plots for Y2 axis - if( $this->y2scale != null ) { - for($i=0; $i< count($this->y2plots); ++$i ) { - $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); - } - } - - if( $this->y2orderback ) { - // Stroke all plots for Y1 axis - for($i=0; $i < count($this->plots); ++$i) { - $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); - $this->plots[$i]->StrokeMargin($this->img); - } - } - - $n = count($this->ynaxis); - for( $i=0; $i < $n; ++$i ) { - $m = count($this->ynplots[$i]); - for( $j=0; $j < $m; ++$j ) { - $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]); - $this->ynplots[$i][$j]->StrokeMargin($this->img); - } - } - - if( $this->iIconDepth == DEPTH_FRONT) { - $this->StrokeIcons(); - } - - if( $this->iDoClipping ) { - // Clipping only supports graphs at 0 and 90 degrees - if( $this->img->a == 0 ) { - $this->img->CopyCanvasH($oldimage,$this->img->img, - $this->img->left_margin,$this->img->top_margin, - $this->img->left_margin,$this->img->top_margin, - $this->img->plotwidth+1,$this->img->plotheight); - } - elseif( $this->img->a == 90 ) { - $adj = ($this->img->height - $this->img->width)/2; - $this->img->CopyCanvasH($oldimage,$this->img->img, - $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, - $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, - $this->img->plotheight+1,$this->img->plotwidth); - } - else { - JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); - } - $this->img->Destroy(); - $this->img->SetCanvasH($oldimage); - } - - $this->xscale->off=$oldoff; - - if( $this->grid_depth == DEPTH_FRONT && !$_csim ) { - $this->ygrid->Stroke(); - $this->xgrid->Stroke(); - } - - // Stroke colored bands - $this->StrokeBands(DEPTH_FRONT,$_csim); - - // Finally draw the axis again since some plots may have nagged - // the axis in the edges. - if( !$_csim ) { - $this->StrokeAxis(); - } - - if( $this->y2scale != null && !$_csim ) { - $this->y2axis->Stroke($this->xscale,false); - } - - if( !$_csim ) { - $this->StrokePlotBox(); - } - - // The titles and legends never gets rotated so make sure - // that the angle is 0 before stroking them - $aa = $this->img->SetAngle(0); - $this->StrokeTitles(); - $this->footer->Stroke($this->img); - $this->legend->Stroke($this->img); - $this->img->SetAngle($aa); - $this->StrokeTexts(); - $this->StrokeTables(); - - if( !$_csim ) { - - $this->img->SetAngle($aa); - - // Draw an outline around the image map - if(_JPG_DEBUG) { - $this->DisplayClientSideaImageMapAreas(); - } - - // Should we do any final image transformation - if( $this->iImgTrans ) { - if( !class_exists('ImgTrans',false) ) { - require_once('jpgraph_imgtrans.php'); - //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); - } - - $tform = new ImgTrans($this->img->img); - $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, - $this->iImgTransDirection,$this->iImgTransHighQ, - $this->iImgTransMinSize,$this->iImgTransFillColor, - $this->iImgTransBorder); - } - - // If the filename is given as the special "__handle" - // then the image handler is returned and the image is NOT - // streamed back - if( $aStrokeFileName == _IMG_HANDLER ) { - return $this->img->img; - } - else { - // Finally stream the generated picture - $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); - } - } - } - - function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') { - $this->iAxisLblBgType = $aType; - $this->iXAxisLblBgFillColor = $aXFColor; - $this->iXAxisLblBgColor = $aXColor; - $this->iYAxisLblBgFillColor = $aYFColor; - $this->iYAxisLblBgColor = $aYColor; - } - - function StrokeAxisLabelBackground() { - // Types - // 0 = No background - // 1 = Only X-labels, length of axis - // 2 = Only Y-labels, length of axis - // 3 = As 1 but extends to width of graph - // 4 = As 2 but extends to height of graph - // 5 = Combination of 3 & 4 - // 6 = Combination of 1 & 2 - - $t = $this->iAxisLblBgType ; - if( $t < 1 ) return; - - // Stroke optional X-axis label background color - if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) { - $this->img->PushColor($this->iXAxisLblBgFillColor); - if( $t == 1 || $t == 6 ) { - $xl = $this->img->left_margin; - $yu = $this->img->height - $this->img->bottom_margin + 1; - $xr = $this->img->width - $this->img->right_margin ; - $yl = $this->img->height-1-$this->frame_weight; - } - else { // t==3 || t==5 - $xl = $this->frame_weight; - $yu = $this->img->height - $this->img->bottom_margin + 1; - $xr = $this->img->width - 1 - $this->frame_weight; - $yl = $this->img->height-1-$this->frame_weight; - } - - $this->img->FilledRectangle($xl,$yu,$xr,$yl); - $this->img->PopColor(); - - // Check if we should add the vertical lines at left and right edge - if( $this->iXAxisLblBgColor !== '' ) { - // Hardcode to one pixel wide - $this->img->SetLineWeight(1); - $this->img->PushColor($this->iXAxisLblBgColor); - if( $t == 1 || $t == 6 ) { - $this->img->Line($xl,$yu,$xl,$yl); - $this->img->Line($xr,$yu,$xr,$yl); - } - else { - $xl = $this->img->width - $this->img->right_margin ; - $this->img->Line($xl,$yu-1,$xr,$yu-1); - } - $this->img->PopColor(); - } - } - - if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) { - $this->img->PushColor($this->iYAxisLblBgFillColor); - if( $t == 2 || $t == 6 ) { - $xl = $this->frame_weight; - $yu = $this->frame_weight+$this->img->top_margin; - $xr = $this->img->left_margin - 1; - $yl = $this->img->height - $this->img->bottom_margin + 1; - } - else { - $xl = $this->frame_weight; - $yu = $this->frame_weight; - $xr = $this->img->left_margin - 1; - $yl = $this->img->height-1-$this->frame_weight; - } - - $this->img->FilledRectangle($xl,$yu,$xr,$yl); - $this->img->PopColor(); - - // Check if we should add the vertical lines at left and right edge - if( $this->iXAxisLblBgColor !== '' ) { - $this->img->PushColor($this->iXAxisLblBgColor); - if( $t == 2 || $t == 6 ) { - $this->img->Line($xl,$yu-1,$xr,$yu-1); - $this->img->Line($xl,$yl-1,$xr,$yl-1); - } - else { - $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin); - } - $this->img->PopColor(); - } - - } - } - - function StrokeAxis($aStrokeLabels=true) { - - if( $aStrokeLabels ) { - $this->StrokeAxisLabelBackground(); - } - - // Stroke axis - if( $this->iAxisStyle != AXSTYLE_SIMPLE ) { - switch( $this->iAxisStyle ) { - case AXSTYLE_BOXIN : - $toppos = SIDE_DOWN; - $bottompos = SIDE_UP; - $leftpos = SIDE_RIGHT; - $rightpos = SIDE_LEFT; - break; - case AXSTYLE_BOXOUT : - $toppos = SIDE_UP; - $bottompos = SIDE_DOWN; - $leftpos = SIDE_LEFT; - $rightpos = SIDE_RIGHT; - break; - case AXSTYLE_YBOXIN: - $toppos = FALSE; - $bottompos = SIDE_UP; - $leftpos = SIDE_RIGHT; - $rightpos = SIDE_LEFT; - break; - case AXSTYLE_YBOXOUT: - $toppos = FALSE; - $bottompos = SIDE_DOWN; - $leftpos = SIDE_LEFT; - $rightpos = SIDE_RIGHT; - break; - default: - JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle); - break; - } - - // By default we hide the first label so it doesn't cross the - // Y-axis in case the positon hasn't been set by the user. - // However, if we use a box we always want the first value - // displayed so we make sure it will be displayed. - $this->xscale->ticks->SupressFirst(false); - - // Now draw the bottom X-axis - $this->xaxis->SetPos('min'); - $this->xaxis->SetLabelSide(SIDE_DOWN); - $this->xaxis->scale->ticks->SetSide($bottompos); - $this->xaxis->Stroke($this->yscale,$aStrokeLabels); - - if( $toppos !== FALSE ) { - // We also want a top X-axis - $this->xaxis = $this->xaxis; - $this->xaxis->SetPos('max'); - $this->xaxis->SetLabelSide(SIDE_UP); - // No title for the top X-axis - if( $aStrokeLabels ) { - $this->xaxis->title->Set(''); - } - $this->xaxis->scale->ticks->SetSide($toppos); - $this->xaxis->Stroke($this->yscale,$aStrokeLabels); - } - - // Stroke the left Y-axis - $this->yaxis->SetPos('min'); - $this->yaxis->SetLabelSide(SIDE_LEFT); - $this->yaxis->scale->ticks->SetSide($leftpos); - $this->yaxis->Stroke($this->xscale,$aStrokeLabels); - - // Stroke the right Y-axis - $this->yaxis->SetPos('max'); - // No title for the right side - if( $aStrokeLabels ) { - $this->yaxis->title->Set(''); - } - $this->yaxis->SetLabelSide(SIDE_RIGHT); - $this->yaxis->scale->ticks->SetSide($rightpos); - $this->yaxis->Stroke($this->xscale,$aStrokeLabels); - } - else { - $this->xaxis->Stroke($this->yscale,$aStrokeLabels); - $this->yaxis->Stroke($this->xscale,$aStrokeLabels); - } - } - - - // Private helper function for backgound image - static function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') { - if( $aImgStr != '' ) { - return Image::CreateFromString($aImgStr); - } - - // Remove case sensitivity and setup appropriate function to create image - // Get file extension. This should be the LAST '.' separated part of the filename - $e = explode('.',$aFile); - $ext = strtolower($e[count($e)-1]); - if ($ext == "jpeg") { - $ext = "jpg"; - } - - if( trim($ext) == '' ) { - $ext = 'png'; // Assume PNG if no extension specified - } - - if( $aImgFormat == '' ) { - $imgtag = $ext; - } - else { - $imgtag = $aImgFormat; - } - - $supported = imagetypes(); - if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || - ( $ext == 'gif' && !($supported & IMG_GIF) ) || - ( $ext == 'png' && !($supported & IMG_PNG) ) || - ( $ext == 'bmp' && !($supported & IMG_WBMP) ) || - ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) { - - JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); - } - - - if( $imgtag == "jpg" || $imgtag == "jpeg") { - $f = "imagecreatefromjpeg"; - $imgtag = "jpg"; - } - else { - $f = "imagecreatefrom".$imgtag; - } - - // Compare specified image type and file extension - if( $imgtag != $ext ) { - //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'"; - JpGraphError::RaiseL(25038, $aImgFormat, $aFile); - } - - $img = @$f($aFile); - if( !$img ) { - JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'"); - } - return $img; - } - - function StrokePlotGrad() { - if( $this->plot_gradtype < 0 ) - return; - - $grad = new Gradient($this->img); - $xl = $this->img->left_margin; - $yt = $this->img->top_margin; - $xr = $xl + $this->img->plotwidth+1 ; - $yb = $yt + $this->img->plotheight ; - $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->plot_gradfrom,$this->plot_gradto,$this->plot_gradtype); - - } - - function StrokeBackgroundGrad() { - if( $this->bkg_gradtype < 0 ) - return; - - $grad = new Gradient($this->img); - if( $this->bkg_gradstyle == BGRAD_PLOT ) { - $xl = $this->img->left_margin; - $yt = $this->img->top_margin; - $xr = $xl + $this->img->plotwidth+1 ; - $yb = $yt + $this->img->plotheight ; - $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); - } - else { - $xl = 0; - $yt = 0; - $xr = $xl + $this->img->width - 1; - $yb = $yt + $this->img->height - 1 ; - if( $this->doshadow ) { - $xr -= $this->shadow_width; - $yb -= $this->shadow_width; - } - if( $this->doframe ) { - $yt += $this->frame_weight; - $yb -= $this->frame_weight; - $xl += $this->frame_weight; - $xr -= $this->frame_weight; - } - $aa = $this->img->SetAngle(0); - $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); - $aa = $this->img->SetAngle($aa); - } - } - - function StrokeFrameBackground() { - if( $this->background_image != '' && $this->background_cflag != '' ) { - JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.'); - } - if( $this->background_image != '' ) { - $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image); - } - elseif( $this->background_cflag != '' ) { - if( ! class_exists('FlagImages',false) ) { - JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.'); - } - $fobj = new FlagImages(FLAGSIZE4); - $dummy=''; - $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy); - $this->background_image_mix = $this->background_cflag_mix; - $this->background_image_type = $this->background_cflag_type; - } - else { - return ; - } - - $bw = ImageSX($bkgimg); - $bh = ImageSY($bkgimg); - - // No matter what the angle is we always stroke the image and frame - // assuming it is 0 degree - $aa = $this->img->SetAngle(0); - - switch( $this->background_image_type ) { - case BGIMG_FILLPLOT: // Resize to just fill the plotarea - $this->FillMarginArea(); - $this->StrokeFrame(); - // Special case to hande 90 degree rotated graph corectly - if( $aa == 90 ) { - $this->img->SetAngle(90); - $this->FillPlotArea(); - $aa = $this->img->SetAngle(0); - $adj = ($this->img->height - $this->img->width)/2; - $this->img->CopyMerge($bkgimg, - $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, - 0,0, - $this->img->plotheight+1,$this->img->plotwidth, - $bw,$bh,$this->background_image_mix); - } - else { - $this->FillPlotArea(); - $this->img->CopyMerge($bkgimg, - $this->img->left_margin,$this->img->top_margin+1, - 0,0,$this->img->plotwidth+1,$this->img->plotheight, - $bw,$bh,$this->background_image_mix); - } - break; - case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit - $hadj=0; $vadj=0; - if( $this->doshadow ) { - $hadj = $this->shadow_width; - $vadj = $this->shadow_width; - } - $this->FillMarginArea(); - $this->FillPlotArea(); - $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj, - $bw,$bh,$this->background_image_mix); - $this->StrokeFrame(); - break; - case BGIMG_COPY: // Just copy the image from left corner, no resizing - $this->FillMarginArea(); - $this->FillPlotArea(); - $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh, - $bw,$bh,$this->background_image_mix); - $this->StrokeFrame(); - break; - case BGIMG_CENTER: // Center original image in the plot area - $this->FillMarginArea(); - $this->FillPlotArea(); - $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); - $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); - $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh, - $bw,$bh,$this->background_image_mix); - $this->StrokeFrame(); - break; - case BGIMG_FREE: // Just copy the image to the specified location - $this->img->CopyMerge($bkgimg, - $this->background_image_xpos,$this->background_image_ypos, - 0,0,$bw,$bh,$bw,$bh,$this->background_image_mix); - $this->StrokeFrame(); // New - break; - default: - JpGraphError::RaiseL(25042);//(" Unknown background image layout"); - } - $this->img->SetAngle($aa); - } - - // Private - // Draw a frame around the image - function StrokeFrame() { - if( !$this->doframe ) return; - - if( $this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { - $c = $this->margin_color; - } - else { - $c = false; - } - - if( $this->doshadow ) { - $this->img->SetColor($this->frame_color); - $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, - $c,$this->shadow_width,$this->shadow_color); - } - elseif( $this->framebevel ) { - if( $c ) { - $this->img->SetColor($this->margin_color); - $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); - } - $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, - $this->framebeveldepth, - $this->framebevelcolor1,$this->framebevelcolor2); - if( $this->framebevelborder ) { - $this->img->SetColor($this->framebevelbordercolor); - $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); - } - } - else { - $this->img->SetLineWeight($this->frame_weight); - if( $c ) { - $this->img->SetColor($this->margin_color); - $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); - } - $this->img->SetColor($this->frame_color); - $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); - } - } - - function FillMarginArea() { - $hadj=0; $vadj=0; - if( $this->doshadow ) { - $hadj = $this->shadow_width; - $vadj = $this->shadow_width; - } - - $this->img->SetColor($this->margin_color); - // $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); - - $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); - $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); - $this->img->FilledRectangle($this->img->left_margin+1, - $this->img->height-$this->img->bottom_margin, - $this->img->width-1-$hadj, - $this->img->height-1-$hadj); - $this->img->FilledRectangle($this->img->width-$this->img->right_margin, - $this->img->top_margin+1, - $this->img->width-1-$hadj, - $this->img->height-$this->img->bottom_margin-1); - } - - function FillPlotArea() { - $this->img->PushColor($this->plotarea_color); - $this->img->FilledRectangle($this->img->left_margin, - $this->img->top_margin, - $this->img->width-$this->img->right_margin, - $this->img->height-$this->img->bottom_margin); - $this->img->PopColor(); - } - - // Stroke the plot area with either a solid color or a background image - function StrokePlotArea() { - // Note: To be consistent we really should take a possible shadow - // into account. However, that causes some problem for the LinearScale class - // since in the current design it does not have any links to class Graph which - // means it has no way of compensating for the adjusted plotarea in case of a - // shadow. So, until I redesign LinearScale we can't compensate for this. - // So just set the two adjustment parameters to zero for now. - $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ; - $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ; - - if( $this->background_image != '' || $this->background_cflag != '' ) { - $this->StrokeFrameBackground(); - } - else { - $aa = $this->img->SetAngle(0); - $this->StrokeFrame(); - $aa = $this->img->SetAngle($aa); - $this->StrokeBackgroundGrad(); - if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { - $this->FillPlotArea(); - } - $this->StrokePlotGrad(); - } - } - - function StrokeIcons() { - $n = count($this->iIcons); - for( $i=0; $i < $n; ++$i ) { - $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); - } - } - - function StrokePlotBox() { - // Should we draw a box around the plot area? - if( $this->boxed ) { - $this->img->SetLineWeight(1); - $this->img->SetLineStyle('solid'); - $this->img->SetColor($this->box_color); - for($i=0; $i < $this->box_weight; ++$i ) { - $this->img->Rectangle( - $this->img->left_margin-$i,$this->img->top_margin-$i, - $this->img->width-$this->img->right_margin+$i, - $this->img->height-$this->img->bottom_margin+$i); - } - } - } - - function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') { - $this->titlebkg_fillstyle = $aStyle; - $this->titlebkg_scolor1 = $aColor1; - $this->titlebkg_scolor2 = $aColor2; - } - - function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) { - $this->titlebackground = $aEnable; - $this->titlebackground_color = $aBackColor; - $this->titlebackground_style = $aStyle; - $this->titlebackground_framecolor = $aFrameColor; - $this->titlebackground_framestyle = $aFrameStyle; - $this->titlebackground_frameweight = $aFrameWeight; - $this->titlebackground_bevelheight = $aBevelHeight ; - } - - - function StrokeTitles() { - - $margin=3; - - if( $this->titlebackground ) { - // Find out height - $this->title->margin += 2 ; - $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin; - if( $this->subtitle->t != '' && !$this->subtitle->hide ) { - $h += $this->subtitle->GetTextHeight($this->img)+$margin+ - $this->subtitle->margin; - $h += 2; - } - if( $this->subsubtitle->t != '' && !$this->subsubtitle->hide ) { - $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+ - $this->subsubtitle->margin; - $h += 2; - } - $this->img->PushColor($this->titlebackground_color); - if( $this->titlebackground_style === TITLEBKG_STYLE1 ) { - // Inside the frame - if( $this->framebevel ) { - $x1 = $y1 = $this->framebeveldepth + 1 ; - $x2 = $this->img->width - $this->framebeveldepth - 2 ; - $this->title->margin += $this->framebeveldepth + 1 ; - $h += $y1 ; - $h += 2; - } - else { - $x1 = $y1 = $this->frame_weight; - $x2 = $this->img->width - $this->frame_weight-1; - } - } - elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) { - // Cover the frame as well - $x1 = $y1 = 0; - $x2 = $this->img->width - 1 ; - } - elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) { - // Cover the frame as well (the difference is that - // for style==3 a bevel frame border is on top - // of the title background) - $x1 = $y1 = 0; - $x2 = $this->img->width - 1 ; - $h += $this->framebeveldepth ; - $this->title->margin += $this->framebeveldepth ; - } - else { - JpGraphError::RaiseL(25043);//('Unknown title background style.'); - } - - if( $this->titlebackground_framestyle === 3 ) { - $h += $this->titlebackground_bevelheight*2 + 1 ; - $this->title->margin += $this->titlebackground_bevelheight ; - } - - if( $this->doshadow ) { - $x2 -= $this->shadow_width ; - } - - $indent=0; - if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { - $indent = $this->titlebackground_bevelheight; - } - - if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) { - $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent, - $this->titlebkg_scolor1, - $this->titlebkg_scolor2); - } - elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) { - $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent, - $this->titlebkg_scolor1, - $this->titlebkg_scolor2,2); - } - else { - // Solid fill - $this->img->FilledRectangle($x1,$y1,$x2,$h); - } - $this->img->PopColor(); - - $this->img->PushColor($this->titlebackground_framecolor); - $this->img->SetLineWeight($this->titlebackground_frameweight); - if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) { - // Frame background - $this->img->Rectangle($x1,$y1,$x2,$h); - } - elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) { - // Bottom line only - $this->img->Line($x1,$h,$x2,$h); - } - elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { - $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight); - } - $this->img->PopColor(); - - // This is clumsy. But we neeed to stroke the whole graph frame if it is - // set to bevel to get the bevel shading on top of the text background - if( $this->framebevel && $this->doframe && $this->titlebackground_style === 3 ) { - $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, - $this->framebeveldepth, - $this->framebevelcolor1,$this->framebevelcolor2); - if( $this->framebevelborder ) { - $this->img->SetColor($this->framebevelbordercolor); - $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); - } - } - } - - // Stroke title - $y = $this->title->margin; - if( $this->title->halign == 'center' ) { - $this->title->Center(0,$this->img->width,$y); - } - elseif( $this->title->halign == 'left' ) { - $this->title->SetPos($this->title->margin+2,$y); - } - elseif( $this->title->halign == 'right' ) { - $indent = 0; - if( $this->doshadow ) { - $indent = $this->shadow_width+2; - } - $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right'); - } - $this->title->Stroke($this->img); - - // ... and subtitle - $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin; - if( $this->subtitle->halign == 'center' ) { - $this->subtitle->Center(0,$this->img->width,$y); - } - elseif( $this->subtitle->halign == 'left' ) { - $this->subtitle->SetPos($this->subtitle->margin+2,$y); - } - elseif( $this->subtitle->halign == 'right' ) { - $indent = 0; - if( $this->doshadow ) - $indent = $this->shadow_width+2; - $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); - } - $this->subtitle->Stroke($this->img); - - // ... and subsubtitle - $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin; - if( $this->subsubtitle->halign == 'center' ) { - $this->subsubtitle->Center(0,$this->img->width,$y); - } - elseif( $this->subsubtitle->halign == 'left' ) { - $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); - } - elseif( $this->subsubtitle->halign == 'right' ) { - $indent = 0; - if( $this->doshadow ) - $indent = $this->shadow_width+2; - $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); - } - $this->subsubtitle->Stroke($this->img); - - // ... and fancy title - $this->tabtitle->Stroke($this->img); - - } - - function StrokeTexts() { - // Stroke any user added text objects - if( $this->texts != null ) { - for($i=0; $i < count($this->texts); ++$i) { - $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); - } - } - - if( $this->y2texts != null && $this->y2scale != null ) { - for($i=0; $i < count($this->y2texts); ++$i) { - $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale); - } - } - - } - - function StrokeTables() { - if( $this->iTables != null ) { - $n = count($this->iTables); - for( $i=0; $i < $n; ++$i ) { - $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); - } - } - } - - function DisplayClientSideaImageMapAreas() { - // Debug stuff - display the outline of the image map areas - $csim=''; - foreach ($this->plots as $p) { - $csim.= $p->GetCSIMareas(); - } - $csim .= $this->legend->GetCSIMareas(); - if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { - $this->img->SetColor($this->csimcolor); - $n = count($coords[0]); - for ($i=0; $i < $n; $i++) { - if ( $coords[1][$i] == 'poly' ) { - preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); - $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); - $m = count($pts[0]); - for ($j=0; $j < $m; $j++) { - $this->img->LineTo($pts[1][$j],$pts[2][$j]); - } - } elseif ( $coords[1][$i] == 'rect' ) { - $pts = preg_split('/,/', $coords[2][$i]); - $this->img->SetStartPoint($pts[0],$pts[1]); - $this->img->LineTo($pts[2],$pts[1]); - $this->img->LineTo($pts[2],$pts[3]); - $this->img->LineTo($pts[0],$pts[3]); - $this->img->LineTo($pts[0],$pts[1]); - } - } - } - } - - // Text scale offset in world coordinates - function SetTextScaleOff($aOff) { - $this->text_scale_off = $aOff; - $this->xscale->text_scale_off = $aOff; - } - - // Text width of bar to be centered in absolute pixels - function SetTextScaleAbsCenterOff($aOff) { - $this->text_scale_abscenteroff = $aOff; - } - - // Get Y min and max values for added lines - function GetLinesYMinMax( $aLines ) { - $n = count($aLines); - if( $n == 0 ) return false; - $min = $aLines[0]->scaleposition ; - $max = $min ; - $flg = false; - for( $i=0; $i < $n; ++$i ) { - if( $aLines[$i]->direction == HORIZONTAL ) { - $flg = true ; - $v = $aLines[$i]->scaleposition ; - if( $min > $v ) $min = $v ; - if( $max < $v ) $max = $v ; - } - } - return $flg ? array($min,$max) : false ; - } - - // Get X min and max values for added lines - function GetLinesXMinMax( $aLines ) { - $n = count($aLines); - if( $n == 0 ) return false ; - $min = $aLines[0]->scaleposition ; - $max = $min ; - $flg = false; - for( $i=0; $i < $n; ++$i ) { - if( $aLines[$i]->direction == VERTICAL ) { - $flg = true ; - $v = $aLines[$i]->scaleposition ; - if( $min > $v ) $min = $v ; - if( $max < $v ) $max = $v ; - } - } - return $flg ? array($min,$max) : false ; - } - - // Get min and max values for all included plots - function GetPlotsYMinMax($aPlots) { - $n = count($aPlots); - $i=0; - do { - list($xmax,$max) = $aPlots[$i]->Max(); - } while( ++$i < $n && !is_numeric($max) ); - - $i=0; - do { - list($xmin,$min) = $aPlots[$i]->Min(); - } while( ++$i < $n && !is_numeric($min) ); - - if( !is_numeric($min) || !is_numeric($max) ) { - JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).'); - } - - for($i=0; $i < $n; ++$i ) { - list($xmax,$ymax)=$aPlots[$i]->Max(); - list($xmin,$ymin)=$aPlots[$i]->Min(); - if (is_numeric($ymax)) $max=max($max,$ymax); - if (is_numeric($ymin)) $min=min($min,$ymin); - } - if( $min == '' ) $min = 0; - if( $max == '' ) $max = 0; - if( $min == 0 && $max == 0 ) { - // Special case if all values are 0 - $min=0;$max=1; - } - return array($min,$max); - } - -} // Class - -//=================================================== -// CLASS LineProperty -// Description: Holds properties for a line -//=================================================== -class LineProperty { - public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=true; - - function __construct($aWeight=1,$aColor='black',$aStyle='solid') { - $this->iWeight = $aWeight; - $this->iColor = $aColor; - $this->iStyle = $aStyle; - } - - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function SetWeight($aWeight) { - $this->iWeight = $aWeight; - } - - function SetStyle($aStyle) { - $this->iStyle = $aStyle; - } - - function Show($aShow=true) { - $this->iShow=$aShow; - } - - function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) { - if( $this->iShow ) { - $aImg->PushColor($this->iColor); - $oldls = $aImg->line_style; - $oldlw = $aImg->line_weight; - $aImg->SetLineWeight($this->iWeight); - $aImg->SetLineStyle($this->iStyle); - $aImg->StyleLine($aX1,$aY1,$aX2,$aY2); - $aImg->PopColor($this->iColor); - $aImg->line_style = $oldls; - $aImg->line_weight = $oldlw; - - } - } -} - -//=================================================== -// CLASS GraphTabTitle -// Description: Draw "tab" titles on top of graphs -//=================================================== -class GraphTabTitle extends Text{ - private $corner = 6 , $posx = 7, $posy = 4; - private $fillcolor='lightyellow',$bordercolor='black'; - private $align = 'left', $width=TABTITLE_WIDTHFIT; - function __construct() { - $this->t = ''; - $this->font_style = FS_BOLD; - $this->hide = true; - $this->color = 'darkred'; - } - - function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') { - $this->color = $aTxtColor; - $this->fillcolor = $aFillColor; - $this->bordercolor = $aBorderColor; - } - - function SetFillColor($aFillColor) { - $this->fillcolor = $aFillColor; - } - - function SetTabAlign($aAlign) { - $this->align = $aAlign; - } - - function SetWidth($aWidth) { - $this->width = $aWidth ; - } - - function Set($t) { - $this->t = $t; - $this->hide = false; - } - - function SetCorner($aD) { - $this->corner = $aD ; - } - - function Stroke($aImg,$aDummy1=null,$aDummy2=null) { - if( $this->hide ) - return; - $this->boxed = false; - $w = $this->GetWidth($aImg) + 2*$this->posx; - $h = $this->GetTextHeight($aImg) + 2*$this->posy; - - $x = $aImg->left_margin; - $y = $aImg->top_margin; - - if( $this->width === TABTITLE_WIDTHFIT ) { - if( $this->align == 'left' ) { - $p = array($x, $y, - $x, $y-$h+$this->corner, - $x + $this->corner,$y-$h, - $x + $w - $this->corner, $y-$h, - $x + $w, $y-$h+$this->corner, - $x + $w, $y); - } - elseif( $this->align == 'center' ) { - $x += round($aImg->plotwidth/2) - round($w/2); - $p = array($x, $y, - $x, $y-$h+$this->corner, - $x + $this->corner, $y-$h, - $x + $w - $this->corner, $y-$h, - $x + $w, $y-$h+$this->corner, - $x + $w, $y); - } - else { - $x += $aImg->plotwidth -$w; - $p = array($x, $y, - $x, $y-$h+$this->corner, - $x + $this->corner,$y-$h, - $x + $w - $this->corner, $y-$h, - $x + $w, $y-$h+$this->corner, - $x + $w, $y); - } - } - else { - if( $this->width === TABTITLE_WIDTHFULL ) { - $w = $aImg->plotwidth ; - } - else { - $w = $this->width ; - } - - // Make the tab fit the width of the plot area - $p = array($x, $y, - $x, $y-$h+$this->corner, - $x + $this->corner,$y-$h, - $x + $w - $this->corner, $y-$h, - $x + $w, $y-$h+$this->corner, - $x + $w, $y); - - } - if( $this->halign == 'left' ) { - $aImg->SetTextAlign('left','bottom'); - $x += $this->posx; - $y -= $this->posy; - } - elseif( $this->halign == 'center' ) { - $aImg->SetTextAlign('center','bottom'); - $x += $w/2; - $y -= $this->posy; - } - else { - $aImg->SetTextAlign('right','bottom'); - $x += $w - $this->posx; - $y -= $this->posy; - } - - $aImg->SetColor($this->fillcolor); - $aImg->FilledPolygon($p); - - $aImg->SetColor($this->bordercolor); - $aImg->Polygon($p,true); - - $aImg->SetColor($this->color); - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $aImg->StrokeText($x,$y,$this->t,0,'center'); - } - -} - -//=================================================== -// CLASS SuperScriptText -// Description: Format a superscript text -//=================================================== -class SuperScriptText extends Text { - private $iSuper=''; - private $sfont_family='',$sfont_style='',$sfont_size=8; - private $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65; - private $iSDir=0; - private $iSimple=false; - - function __construct($aTxt='',$aSuper='',$aXAbsPos=0,$aYAbsPos=0) { - parent::__construct($aTxt,$aXAbsPos,$aYAbsPos); - $this->iSuper = $aSuper; - } - - function FromReal($aVal,$aPrecision=2) { - // Convert a floating point number to scientific notation - $neg=1.0; - if( $aVal < 0 ) { - $neg = -1.0; - $aVal = -$aVal; - } - - $l = floor(log10($aVal)); - $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision)); - $a *= $neg; - if( $this->iSimple && ($a == 1 || $a==-1) ) $a = ''; - - if( $a != '' ) { - $this->t = $a.' * 10'; - } - else { - if( $neg == 1 ) { - $this->t = '10'; - } - else { - $this->t = '-10'; - } - } - $this->iSuper = $l; - } - - function Set($aTxt,$aSuper='') { - $this->t = $aTxt; - $this->iSuper = $aSuper; - } - - function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) { - $this->sfont_family = $aFontFam; - $this->sfont_style = $aFontStyle; - $this->sfont_size = $aFontSize; - } - - // Total width of text - function GetWidth($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $w = $aImg->GetTextWidth($this->t); - $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); - $w += $aImg->GetTextWidth($this->iSuper); - $w += $this->iSuperMargin; - return $w; - } - - // Hight of font (approximate the height of the text) - function GetFontHeight($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $h = $aImg->GetFontHeight(); - $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); - $h += $aImg->GetFontHeight(); - return $h; - } - - // Hight of text - function GetTextHeight($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $h = $aImg->GetTextHeight($this->t); - $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); - $h += $aImg->GetTextHeight($this->iSuper); - return $h; - } - - function Stroke($aImg,$ax=-1,$ay=-1) { - - // To position the super script correctly we need different - // cases to handle the alignmewnt specified since that will - // determine how we can interpret the x,y coordinates - - $w = parent::GetWidth($aImg); - $h = parent::GetTextHeight($aImg); - switch( $this->valign ) { - case 'top': - $sy = $this->y; - break; - case 'center': - $sy = $this->y - $h/2; - break; - case 'bottom': - $sy = $this->y - $h; - break; - default: - JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text'); - break; - } - - switch( $this->halign ) { - case 'left': - $sx = $this->x + $w; - break; - case 'center': - $sx = $this->x + $w/2; - break; - case 'right': - $sx = $this->x; - break; - default: - JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text'); - break; - } - - $sx += $this->iSuperMargin; - $sy += $this->iVertOverlap; - - // Should we automatically determine the font or - // has the user specified it explicetly? - if( $this->sfont_family == '' ) { - if( $this->font_family <= FF_FONT2 ) { - if( $this->font_family == FF_FONT0 ) { - $sff = FF_FONT0; - } - elseif( $this->font_family == FF_FONT1 ) { - if( $this->font_style == FS_NORMAL ) { - $sff = FF_FONT0; - } - else { - $sff = FF_FONT1; - } - } - else { - $sff = FF_FONT1; - } - $sfs = $this->font_style; - $sfz = $this->font_size; - } - else { - // TTF fonts - $sff = $this->font_family; - $sfs = $this->font_style; - $sfz = floor($this->font_size*$this->iSuperScale); - if( $sfz < 8 ) $sfz = 8; - } - $this->sfont_family = $sff; - $this->sfont_style = $sfs; - $this->sfont_size = $sfz; - } - else { - $sff = $this->sfont_family; - $sfs = $this->sfont_style; - $sfz = $this->sfont_size; - } - - parent::Stroke($aImg,$ax,$ay); - - // For the builtin fonts we need to reduce the margins - // since the bounding bx reported for the builtin fonts - // are much larger than for the TTF fonts. - if( $sff <= FF_FONT2 ) { - $sx -= 2; - $sy += 3; - } - - $aImg->SetTextAlign('left','bottom'); - $aImg->SetFont($sff,$sfs,$sfz); - $aImg->PushColor($this->color); - $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left'); - $aImg->PopColor(); - } -} - - -//=================================================== -// CLASS Grid -// Description: responsible for drawing grid lines in graph -//=================================================== -class Grid { - protected $img; - protected $scale; - protected $majorcolor='#DDDDDD',$minorcolor='#EEEEEE'; - protected $majortype='solid',$minortype='solid'; - protected $show=false, $showMinor=false,$majorweight=1,$minorweight=1; - protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF'); - - function __construct($aAxis) { - $this->scale = $aAxis->scale; - $this->img = $aAxis->img; - } - - function SetColor($aMajColor,$aMinColor=false) { - $this->majorcolor=$aMajColor; - if( $aMinColor === false ) { - $aMinColor = $aMajColor ; - } - $this->minorcolor = $aMinColor; - } - - function SetWeight($aMajorWeight,$aMinorWeight=1) { - $this->majorweight=$aMajorWeight; - $this->minorweight=$aMinorWeight; - } - - // Specify if grid should be dashed, dotted or solid - function SetLineStyle($aMajorType,$aMinorType='solid') { - $this->majortype = $aMajorType; - $this->minortype = $aMinorType; - } - - function SetStyle($aMajorType,$aMinorType='solid') { - $this->SetLineStyle($aMajorType,$aMinorType); - } - - // Decide if both major and minor grid should be displayed - function Show($aShowMajor=true,$aShowMinor=false) { - $this->show=$aShowMajor; - $this->showMinor=$aShowMinor; - } - - function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') { - $this->fill = $aFlg; - $this->fillcolor = array( $aColor1, $aColor2 ); - } - - // Display the grid - function Stroke() { - if( $this->showMinor && !$this->scale->textscale ) { - $this->DoStroke($this->scale->ticks->ticks_pos,$this->minortype,$this->minorcolor,$this->minorweight); - $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight); - } - else { - $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight); - } - } - - //-------------- - // Private methods - // Draw the grid - function DoStroke($aTicksPos,$aType,$aColor,$aWeight) { - if( !$this->show ) return; - $nbrgrids = count($aTicksPos); - - if( $this->scale->type == 'y' ) { - $xl=$this->img->left_margin; - $xr=$this->img->width-$this->img->right_margin; - - if( $this->fill ) { - // Draw filled areas - $y2 = $aTicksPos[0]; - $i=1; - while( $i < $nbrgrids ) { - $y1 = $y2; - $y2 = $aTicksPos[$i++]; - $this->img->SetColor($this->fillcolor[$i & 1]); - $this->img->FilledRectangle($xl,$y1,$xr,$y2); - } - } - - $this->img->SetColor($aColor); - $this->img->SetLineWeight($aWeight); - - // Draw grid lines - switch( $aType ) { - case 'solid': $style = LINESTYLE_SOLID; break; - case 'dotted': $style = LINESTYLE_DOTTED; break; - case 'dashed': $style = LINESTYLE_DASHED; break; - case 'longdashed': $style = LINESTYLE_LONGDASH; break; - default: - $style = LINESTYLE_SOLID; break; - } - - for($i=0; $i < $nbrgrids; ++$i) { - $y=$aTicksPos[$i]; - $this->img->StyleLine($xl,$y,$xr,$y,$style); - } - } - elseif( $this->scale->type == 'x' ) { - $yu=$this->img->top_margin; - $yl=$this->img->height-$this->img->bottom_margin; - $limit=$this->img->width-$this->img->right_margin; - - if( $this->fill ) { - // Draw filled areas - $x2 = $aTicksPos[0]; - $i=1; - while( $i < $nbrgrids ) { - $x1 = $x2; - $x2 = min($aTicksPos[$i++],$limit) ; - $this->img->SetColor($this->fillcolor[$i & 1]); - $this->img->FilledRectangle($x1,$yu,$x2,$yl); - } - } - - $this->img->SetColor($aColor); - $this->img->SetLineWeight($aWeight); - - // We must also test for limit since we might have - // an offset and the number of ticks is calculated with - // assumption offset==0 so we might end up drawing one - // to many gridlines - $i=0; - $x=$aTicksPos[$i]; - while( $iimg->Line($x,$yl,$x,$yu); - elseif( $aType == 'dotted' ) $this->img->DashedLine($x,$yl,$x,$yu,1,6); - elseif( $aType == 'dashed' ) $this->img->DashedLine($x,$yl,$x,$yu,2,4); - elseif( $aType == 'longdashed' ) $this->img->DashedLine($x,$yl,$x,$yu,8,6); - ++$i; - } - } - else { - JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']'); - } - return true; - } -} // Class - -//=================================================== -// CLASS Axis -// Description: Defines X and Y axis. Notes that at the -// moment the code is not really good since the axis on -// several occasion must know wheter it's an X or Y axis. -// This was a design decision to make the code easier to -// follow. -//=================================================== -class AxisPrototype { - public $scale=null; - public $img=null; - public $hide=false,$hide_labels=false; - public $title=null; - public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0; - public $tick_step=1; - public $pos = false; - public $ticks_label = array(); - - protected $weight=1; - protected $color=array(0,0,0),$label_color=array(0,0,0); - protected $ticks_label_colors=null; - protected $show_first_label=true,$show_last_label=true; - protected $label_step=1; // Used by a text axis to specify what multiple of major steps - // should be labeled. - protected $labelPos=0; // Which side of the axis should the labels be? - protected $title_adjust,$title_margin,$title_side=SIDE_LEFT; - protected $tick_label_margin=5; - protected $label_halign = '',$label_valign = '', $label_para_align='left'; - protected $hide_line=false; - protected $iDeltaAbsPos=0; - - function __construct($img,$aScale,$color = array(0,0,0)) { - $this->img = $img; - $this->scale = $aScale; - $this->color = $color; - $this->title=new Text(''); - - if( $aScale->type == 'y' ) { - $this->title_margin = 25; - $this->title_adjust = 'middle'; - $this->title->SetOrientation(90); - $this->tick_label_margin=7; - $this->labelPos=SIDE_LEFT; - } - else { - $this->title_margin = 5; - $this->title_adjust = 'high'; - $this->title->SetOrientation(0); - $this->tick_label_margin=5; - $this->labelPos=SIDE_DOWN; - $this->title_side=SIDE_DOWN; - } - } - - function SetLabelFormat($aFormStr) { - $this->scale->ticks->SetLabelFormat($aFormStr); - } - - function SetLabelFormatString($aFormStr,$aDate=false) { - $this->scale->ticks->SetLabelFormat($aFormStr,$aDate); - } - - function SetLabelFormatCallback($aFuncName) { - $this->scale->ticks->SetFormatCallback($aFuncName); - } - - function SetLabelAlign($aHAlign,$aVAlign='top',$aParagraphAlign='left') { - $this->label_halign = $aHAlign; - $this->label_valign = $aVAlign; - $this->label_para_align = $aParagraphAlign; - } - - // Don't display the first label - function HideFirstTickLabel($aShow=false) { - $this->show_first_label=$aShow; - } - - function HideLastTickLabel($aShow=false) { - $this->show_last_label=$aShow; - } - - // Manually specify the major and (optional) minor tick position and labels - function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { - $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels); - } - - // Manually specify major tick positions and optional labels - function SetMajTickPositions($aMajPos,$aLabels=NULL) { - $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels); - } - - // Hide minor or major tick marks - function HideTicks($aHideMinor=true,$aHideMajor=true) { - $this->scale->ticks->SupressMinorTickMarks($aHideMinor); - $this->scale->ticks->SupressTickMarks($aHideMajor); - } - - // Hide zero label - function HideZeroLabel($aFlag=true) { - $this->scale->ticks->SupressZeroLabel(); - } - - function HideFirstLastLabel() { - // The two first calls to ticks method will supress - // automatically generated scale values. However, that - // will not affect manually specified value, e.g text-scales. - // therefor we also make a kludge here to supress manually - // specified scale labels. - $this->scale->ticks->SupressLast(); - $this->scale->ticks->SupressFirst(); - $this->show_first_label = false; - $this->show_last_label = false; - } - - // Hide the axis - function Hide($aHide=true) { - $this->hide=$aHide; - } - - // Hide the actual axis-line, but still print the labels - function HideLine($aHide=true) { - $this->hide_line = $aHide; - } - - function HideLabels($aHide=true) { - $this->hide_labels = $aHide; - } - - // Weight of axis - function SetWeight($aWeight) { - $this->weight = $aWeight; - } - - // Axis color - function SetColor($aColor,$aLabelColor=false) { - $this->color = $aColor; - if( !$aLabelColor ) $this->label_color = $aColor; - else $this->label_color = $aLabelColor; - } - - // Title on axis - function SetTitle($aTitle,$aAdjustAlign='high') { - $this->title->Set($aTitle); - $this->title_adjust=$aAdjustAlign; - } - - // Specify distance from the axis - function SetTitleMargin($aMargin) { - $this->title_margin=$aMargin; - } - - // Which side of the axis should the axis title be? - function SetTitleSide($aSideOfAxis) { - $this->title_side = $aSideOfAxis; - } - - function SetTickSide($aDir) { - $this->scale->ticks->SetSide($aDir); - } - - function SetTickSize($aMajSize,$aMinSize=3) { - $this->scale->ticks->SetSize($aMajSize,$aMinSize=3); - } - - // Specify text labels for the ticks. One label for each data point - function SetTickLabels($aLabelArray,$aLabelColorArray=null) { - $this->ticks_label = $aLabelArray; - $this->ticks_label_colors = $aLabelColorArray; - } - - function SetLabelMargin($aMargin) { - $this->tick_label_margin=$aMargin; - } - - // Specify that every $step of the ticks should be displayed starting - // at $start - function SetTextTickInterval($aStep,$aStart=0) { - $this->scale->ticks->SetTextLabelStart($aStart); - $this->tick_step=$aStep; - } - - // Specify that every $step tick mark should have a label - // should be displayed starting - function SetTextLabelInterval($aStep) { - if( $aStep < 1 ) { - JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1."); - } - $this->label_step=$aStep; - } - - function SetLabelSide($aSidePos) { - $this->labelPos=$aSidePos; - } - - // Set the font - function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { - $this->font_family = $aFamily; - $this->font_style = $aStyle; - $this->font_size = $aSize; - } - - // Position for axis line on the "other" scale - function SetPos($aPosOnOtherScale) { - $this->pos=$aPosOnOtherScale; - } - - // Set the position of the axis to be X-pixels delta to the right - // of the max X-position (used to position the multiple Y-axis) - function SetPosAbsDelta($aDelta) { - $this->iDeltaAbsPos=$aDelta; - } - - // Specify the angle for the tick labels - function SetLabelAngle($aAngle) { - $this->label_angle = $aAngle; - } - -} // Class - - -//=================================================== -// CLASS Axis -// Description: Defines X and Y axis. Notes that at the -// moment the code is not really good since the axis on -// several occasion must know wheter it's an X or Y axis. -// This was a design decision to make the code easier to -// follow. -//=================================================== -class Axis extends AxisPrototype { - - function __construct($img,$aScale,$color='black') { - parent::__construct($img,$aScale,$color); - } - - // Stroke the axis. - function Stroke($aOtherAxisScale,$aStrokeLabels=true) { - if( $this->hide ) - return; - if( is_numeric($this->pos) ) { - $pos=$aOtherAxisScale->Translate($this->pos); - } - else { // Default to minimum of other scale if pos not set - if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos == 'min' ) { - $pos = $aOtherAxisScale->scale_abs[0]; - } - elseif($this->pos == "max") { - $pos = $aOtherAxisScale->scale_abs[1]; - } - else { // If negative set x-axis at 0 - $this->pos=0; - $pos=$aOtherAxisScale->Translate(0); - } - } - $pos += $this->iDeltaAbsPos; - $this->img->SetLineWeight($this->weight); - $this->img->SetColor($this->color); - $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); - if( $this->scale->type == "x" ) { - if( !$this->hide_line ) { - $this->img->FilledRectangle($this->img->left_margin,$pos,$this->img->width-$this->img->right_margin,$pos+$this->weight-1); - } - if( $this->title_side == SIDE_DOWN ) { - $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; - $yalign = 'top'; - } - else { - $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin; - $yalign = 'bottom'; - } - - if( $this->title_adjust=='high' ) { - $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign); - } - elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) { - $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign); - } - elseif($this->title_adjust=='low') { - $this->title->SetPos($this->img->left_margin,$y,'left',$yalign); - } - else { - JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); - } - } - elseif( $this->scale->type == "y" ) { - // Add line weight to the height of the axis since - // the x-axis could have a width>1 and we want the axis to fit nicely together. - if( !$this->hide_line ) { - $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin,$pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); - } - $x=$pos ; - if( $this->title_side == SIDE_LEFT ) { - $x -= $this->title_margin; - $x -= $this->title->margin; - $halign = 'right'; - } - else { - $x += $this->title_margin; - $x += $this->title->margin; - $halign = 'left'; - } - // If the user has manually specified an hor. align - // then we override the automatic settings with this - // specifed setting. Since default is 'left' we compare - // with that. (This means a manually set 'left' align - // will have no effect.) - if( $this->title->halign != 'left' ) { - $halign = $this->title->halign; - } - if( $this->title_adjust == 'high' ) { - $this->title->SetPos($x,$this->img->top_margin,$halign,'top'); - } - elseif($this->title_adjust=='middle' || $this->title_adjust=='center') { - $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); - } - elseif($this->title_adjust=='low') { - $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,'bottom'); - } - else { - JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')'); - } - } - $this->scale->ticks->Stroke($this->img,$this->scale,$pos); - if( $aStrokeLabels ) { - if( !$this->hide_labels ) { - $this->StrokeLabels($pos); - } - $this->title->Stroke($this->img); - } - } - - //--------------- - // PRIVATE METHODS - // Draw all the tick labels on major tick marks - function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) { - - if( is_array($this->label_color) && count($this->label_color) > 3 ) { - $this->ticks_label_colors = $this->label_color; - $this->img->SetColor($this->label_color[0]); - } - else { - $this->img->SetColor($this->label_color); - } - $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); - $yoff=$this->img->GetFontHeight()/2; - - // Only draw labels at major tick marks - $nbr = count($this->scale->ticks->maj_ticks_label); - - // We have the option to not-display the very first mark - // (Usefull when the first label might interfere with another - // axis.) - $i = $this->show_first_label ? 0 : 1 ; - if( !$this->show_last_label ) { - --$nbr; - } - // Now run through all labels making sure we don't overshoot the end - // of the scale. - $ncolor=0; - if( isset($this->ticks_label_colors) ) { - $ncolor=count($this->ticks_label_colors); - } - while( $i < $nbr ) { - // $tpos holds the absolute text position for the label - $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; - - // Note. the $limit is only used for the x axis since we - // might otherwise overshoot if the scale has been centered - // This is due to us "loosing" the last tick mark if we center. - if( $this->scale->type == 'x' && $tpos > $this->img->width-$this->img->right_margin+1 ) { - return; - } - // we only draw every $label_step label - if( ($i % $this->label_step)==0 ) { - - // Set specific label color if specified - if( $ncolor > 0 ) { - $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); - } - - // If the label has been specified use that and in other case - // just label the mark with the actual scale value - $m=$this->scale->ticks->GetMajor(); - - // ticks_label has an entry for each data point and is the array - // that holds the labels set by the user. If the user hasn't - // specified any values we use whats in the automatically asigned - // labels in the maj_ticks_label - if( isset($this->ticks_label[$i*$m]) ) { - $label=$this->ticks_label[$i*$m]; - } - else { - if( $aAbsLabel ) { - $label=abs($this->scale->ticks->maj_ticks_label[$i]); - } - else { - $label=$this->scale->ticks->maj_ticks_label[$i]; - } - - // We number the scale from 1 and not from 0 so increase by one - if( $this->scale->textscale && - $this->scale->ticks->label_formfunc == '' && - ! $this->scale->ticks->HaveManualLabels() ) { - - ++$label; - - } - } - - if( $this->scale->type == "x" ) { - if( $this->labelPos == SIDE_DOWN ) { - if( $this->label_angle==0 || $this->label_angle==90 ) { - if( $this->label_halign=='' && $this->label_valign=='') { - $this->img->SetTextAlign('center','top'); - } - else { - $this->img->SetTextAlign($this->label_halign,$this->label_valign); - } - - } - else { - if( $this->label_halign=='' && $this->label_valign=='') { - $this->img->SetTextAlign("right","top"); - } - else { - $this->img->SetTextAlign($this->label_halign,$this->label_valign); - } - } - $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label, - $this->label_angle,$this->label_para_align); - } - else { - if( $this->label_angle==0 || $this->label_angle==90 ) { - if( $this->label_halign=='' && $this->label_valign=='') { - $this->img->SetTextAlign("center","bottom"); - } - else { - $this->img->SetTextAlign($this->label_halign,$this->label_valign); - } - } - else { - if( $this->label_halign=='' && $this->label_valign=='') { - $this->img->SetTextAlign("right","bottom"); - } - else { - $this->img->SetTextAlign($this->label_halign,$this->label_valign); - } - } - $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label, - $this->label_angle,$this->label_para_align); - } - } - else { - // scale->type == "y" - //if( $this->label_angle!=0 ) - //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis"); - if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis - if( $this->label_halign=='' && $this->label_valign=='') { - $this->img->SetTextAlign("right","center"); - } - else { - $this->img->SetTextAlign($this->label_halign,$this->label_valign); - } - $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); - } - else { // To the right of the y-axis - if( $this->label_halign=='' && $this->label_valign=='') { - $this->img->SetTextAlign("left","center"); - } - else { - $this->img->SetTextAlign($this->label_halign,$this->label_valign); - } - $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); - } - } - } - ++$i; - } - } - -} - - -//=================================================== -// CLASS Ticks -// Description: Abstract base class for drawing linear and logarithmic -// tick marks on axis -//=================================================== -class Ticks { - public $label_formatstr=''; // C-style format string to use for labels - public $label_formfunc=''; - public $label_dateformatstr=''; - public $direction=1; // Should ticks be in(=1) the plot area or outside (=-1) - public $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false; - public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), - $ticks_pos = array(), $maj_ticks_label = array(); - public $precision; - - protected $minor_abs_size=3, $major_abs_size=5; - protected $scale; - protected $is_set=false; - protected $supress_zerolabel=false,$supress_first=false; - protected $mincolor='',$majcolor=''; - protected $weight=1; - protected $label_usedateformat=FALSE; - - function __construct($aScale) { - $this->scale=$aScale; - $this->precision = -1; - } - - // Set format string for automatic labels - function SetLabelFormat($aFormatString,$aDate=FALSE) { - $this->label_formatstr=$aFormatString; - $this->label_usedateformat=$aDate; - } - - function SetLabelDateFormat($aFormatString) { - $this->label_dateformatstr=$aFormatString; - } - - function SetFormatCallback($aCallbackFuncName) { - $this->label_formfunc = $aCallbackFuncName; - } - - // Don't display the first zero label - function SupressZeroLabel($aFlag=true) { - $this->supress_zerolabel=$aFlag; - } - - // Don't display minor tick marks - function SupressMinorTickMarks($aHide=true) { - $this->supress_minor_tickmarks=$aHide; - } - - // Don't display major tick marks - function SupressTickMarks($aHide=true) { - $this->supress_tickmarks=$aHide; - } - - // Hide the first tick mark - function SupressFirst($aHide=true) { - $this->supress_first=$aHide; - } - - // Hide the last tick mark - function SupressLast($aHide=true) { - $this->supress_last=$aHide; - } - - // Size (in pixels) of minor tick marks - function GetMinTickAbsSize() { - return $this->minor_abs_size; - } - - // Size (in pixels) of major tick marks - function GetMajTickAbsSize() { - return $this->major_abs_size; - } - - function SetSize($aMajSize,$aMinSize=3) { - $this->major_abs_size = $aMajSize; - $this->minor_abs_size = $aMinSize; - } - - // Have the ticks been specified - function IsSpecified() { - return $this->is_set; - } - - function SetSide($aSide) { - $this->direction=$aSide; - } - - // Which side of the axis should the ticks be on - function SetDirection($aSide=SIDE_RIGHT) { - $this->direction=$aSide; - } - - // Set colors for major and minor tick marks - function SetMarkColor($aMajorColor,$aMinorColor='') { - $this->SetColor($aMajorColor,$aMinorColor); - } - - function SetColor($aMajorColor,$aMinorColor='') { - $this->majcolor=$aMajorColor; - - // If not specified use same as major - if( $aMinorColor == '' ) { - $this->mincolor=$aMajorColor; - } - else { - $this->mincolor=$aMinorColor; - } - } - - function SetWeight($aWeight) { - $this->weight=$aWeight; - } - -} // Class - -//=================================================== -// CLASS LinearTicks -// Description: Draw linear ticks on axis -//=================================================== -class LinearTicks extends Ticks { - public $minor_step=1, $major_step=2; - public $xlabel_offset=0,$xtick_offset=0; - private $label_offset=0; // What offset should the displayed label have - // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc - private $text_label_start=0; - private $iManualTickPos = NULL, $iManualMinTickPos = NULL, $iManualTickLabels = NULL; - private $iAdjustForDST = false; // If a date falls within the DST period add one hour to the diaplyed time - - function __construct() { - $this->precision = -1; - } - - // Return major step size in world coordinates - function GetMajor() { - return $this->major_step; - } - - // Return minor step size in world coordinates - function GetMinor() { - return $this->minor_step; - } - - // Set Minor and Major ticks (in world coordinates) - function Set($aMajStep,$aMinStep=false) { - if( $aMinStep==false ) { - $aMinStep=$aMajStep; - } - - if( $aMajStep <= 0 || $aMinStep <= 0 ) { - JpGraphError::RaiseL(25064); - //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); - } - - $this->major_step=$aMajStep; - $this->minor_step=$aMinStep; - $this->is_set = true; - } - - function SetMajTickPositions($aMajPos,$aLabels=NULL) { - $this->SetTickPositions($aMajPos,NULL,$aLabels); - } - - function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { - if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) { - JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()'); - return; - } - $n=count($aMajPos); - if( is_array($aLabels) && (count($aLabels) != $n) ) { - JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.'); - } - $this->iManualTickPos = $aMajPos; - $this->iManualMinTickPos = $aMinPos; - $this->iManualTickLabels = $aLabels; - } - - function HaveManualLabels() { - return count($this->iManualTickLabels) > 0; - } - - // Specify all the tick positions manually and possible also the exact labels - function _doManualTickPos($aScale) { - $n=count($this->iManualTickPos); - $m=count($this->iManualMinTickPos); - $doLbl=count($this->iManualTickLabels) > 0; - - $this->maj_ticks_pos = array(); - $this->maj_ticklabels_pos = array(); - $this->ticks_pos = array(); - - // Now loop through the supplied positions and translate them to screen coordinates - // and store them in the maj_label_positions - $minScale = $aScale->scale[0]; - $maxScale = $aScale->scale[1]; - $j=0; - for($i=0; $i < $n ; ++$i ) { - // First make sure that the first tick is not lower than the lower scale value - if( !isset($this->iManualTickPos[$i]) || $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) { - continue; - } - - $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]); - $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j]; - - // Set the minor tick marks the same as major if not specified - if( $m <= 0 ) { - $this->ticks_pos[$j] = $this->maj_ticks_pos[$j]; - } - if( $doLbl ) { - $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i]; - } - else { - $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n); - } - ++$j; - } - - // Some sanity check - if( count($this->maj_ticks_pos) < 2 ) { - JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.'); - } - - // Setup the minor tick marks - $j=0; - for($i=0; $i < $m; ++$i ) { - if( empty($this->iManualMinTickPos[$i]) || $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) { - continue; - } - $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]); - ++$j; - } - } - - function _doAutoTickPos($aScale) { - $maj_step_abs = $aScale->scale_factor*$this->major_step; - $min_step_abs = $aScale->scale_factor*$this->minor_step; - - if( $min_step_abs==0 || $maj_step_abs==0 ) { - JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')"); - } - // We need to make this an int since comparing it below - // with the result from round() can give wrong result, such that - // (40 < 40) == TRUE !!! - $limit = (int)$aScale->scale_abs[1]; - - if( $aScale->textscale ) { - // This can only be true for a X-scale (horizontal) - // Define ticks for a text scale. This is slightly different from a - // normal linear type of scale since the position might be adjusted - // and the labels start at on - $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset; - $start_abs=$aScale->scale_factor*$this->text_label_start; - $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; - - $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs; - for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) { - // Apply format to label - $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks); - $label+=$this->major_step; - - // The x-position of the tick marks can be different from the labels. - // Note that we record the tick position (not the label) so that the grid - // happen upon tick marks and not labels. - $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs; - $this->maj_ticks_pos[$i]=$xtick; - $this->maj_ticklabels_pos[$i] = round($x); - $x += $maj_step_abs; - } - } - else { - $label = $aScale->GetMinVal(); - $abs_pos = $aScale->scale_abs[0]; - $j=0; $i=0; - $step = round($maj_step_abs/$min_step_abs); - if( $aScale->type == "x" ) { - // For a normal linear type of scale the major ticks will always be multiples - // of the minor ticks. In order to avoid any rounding issues the major ticks are - // defined as every "step" minor ticks and not calculated separately - $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; - while( round($abs_pos) <= $limit ) { - $this->ticks_pos[] = round($abs_pos); - $this->ticks_label[] = $label; - if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) { - $this->maj_ticks_pos[$j] = round($abs_pos); - $this->maj_ticklabels_pos[$j] = round($abs_pos); - $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); - ++$j; - } - ++$i; - $abs_pos += $min_step_abs; - $label+=$this->minor_step; - } - } - elseif( $aScale->type == "y" ) { - $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; - while( round($abs_pos) >= $limit ) { - $this->ticks_pos[$i] = round($abs_pos); - $this->ticks_label[$i]=$label; - if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) { - $this->maj_ticks_pos[$j] = round($abs_pos); - $this->maj_ticklabels_pos[$j] = round($abs_pos); - $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); - ++$j; - } - ++$i; - $abs_pos += $min_step_abs; - $label += $this->minor_step; - } - } - } - } - - function AdjustForDST($aFlg=true) { - $this->iAdjustForDST = $aFlg; - } - - - function _doLabelFormat($aVal,$aIdx,$aNbrTicks) { - - // If precision hasn't been specified set it to a sensible value - if( $this->precision==-1 ) { - $t = log10($this->minor_step); - if( $t > 0 ) { - $precision = 0; - } - else { - $precision = -floor($t); - } - } - else { - $precision = $this->precision; - } - - if( $this->label_formfunc != '' ) { - $f=$this->label_formfunc; - if( $this->label_formatstr == '' ) { - $l = call_user_func($f,$aVal); - } - else { - $l = sprintf($this->label_formatstr, call_user_func($f,$aVal)); - } - } - elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) { - if( $this->label_usedateformat ) { - // Adjust the value to take daylight savings into account - if (date("I",$aVal)==1 && $this->iAdjustForDST ) { - // DST - $aVal+=3600; - } - - $l = date($this->label_formatstr,$aVal); - if( $this->label_formatstr == 'W' ) { - // If we use week formatting then add a single 'w' in front of the - // week number to differentiate it from dates - $l = 'w'.$l; - } - } - else { - if( $this->label_dateformatstr !== '' ) { - // Adjust the value to take daylight savings into account - if (date("I",$aVal)==1 && $this->iAdjustForDST ) { - // DST - $aVal+=3600; - } - - $l = date($this->label_dateformatstr,$aVal); - if( $this->label_formatstr == 'W' ) { - // If we use week formatting then add a single 'w' in front of the - // week number to differentiate it from dates - $l = 'w'.$l; - } - } - else { - $l = sprintf($this->label_formatstr,$aVal); - } - } - } - else { - $l = sprintf('%01.'.$precision.'f',round($aVal,$precision)); - } - - if( ($this->supress_zerolabel && $l==0) || ($this->supress_first && $aIdx==0) || ($this->supress_last && $aIdx==$aNbrTicks-1) ) { - $l=''; - } - return $l; - } - - // Stroke ticks on either X or Y axis - function _StrokeTicks($aImg,$aScale,$aPos) { - $hor = $aScale->type == 'x'; - $aImg->SetLineWeight($this->weight); - - // We need to make this an int since comparing it below - // with the result from round() can give wrong result, such that - // (40 < 40) == TRUE !!! - $limit = (int)$aScale->scale_abs[1]; - - // A text scale doesn't have any minor ticks - if( !$aScale->textscale ) { - // Stroke minor ticks - $yu = $aPos - $this->direction*$this->GetMinTickAbsSize(); - $xr = $aPos + $this->direction*$this->GetMinTickAbsSize(); - $n = count($this->ticks_pos); - for($i=0; $i < $n; ++$i ) { - if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { - if( $this->mincolor != '') { - $aImg->PushColor($this->mincolor); - } - if( $hor ) { - //if( $this->ticks_pos[$i] <= $limit ) - $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); - } - else { - //if( $this->ticks_pos[$i] >= $limit ) - $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); - } - if( $this->mincolor != '' ) { - $aImg->PopColor(); - } - } - } - } - - // Stroke major ticks - $yu = $aPos - $this->direction*$this->GetMajTickAbsSize(); - $xr = $aPos + $this->direction*$this->GetMajTickAbsSize(); - $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; - $n = count($this->maj_ticks_pos); - for($i=0; $i < $n ; ++$i ) { - if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { - if( $this->majcolor != '') { - $aImg->PushColor($this->majcolor); - } - if( $hor ) { - //if( $this->maj_ticks_pos[$i] <= $limit ) - $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); - } - else { - //if( $this->maj_ticks_pos[$i] >= $limit ) - $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); - } - if( $this->majcolor != '') { - $aImg->PopColor(); - } - } - } - - } - - // Draw linear ticks - function Stroke($aImg,$aScale,$aPos) { - if( $this->iManualTickPos != NULL ) { - $this->_doManualTickPos($aScale); - } - else { - $this->_doAutoTickPos($aScale); - } - $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' ); - } - - //--------------- - // PRIVATE METHODS - // Spoecify the offset of the displayed tick mark with the tick "space" - // Legal values for $o is [0,1] used to adjust where the tick marks and label - // should be positioned within the major tick-size - // $lo specifies the label offset and $to specifies the tick offset - // this comes in handy for example in bar graphs where we wont no offset for the - // tick but have the labels displayed halfway under the bars. - function SetXLabelOffset($aLabelOff,$aTickOff=-1) { - $this->xlabel_offset=$aLabelOff; - if( $aTickOff==-1 ) { - // Same as label offset - $this->xtick_offset=$aLabelOff; - } - else { - $this->xtick_offset=$aTickOff; - } - if( $aLabelOff>0 ) { - $this->SupressLast(); // The last tick wont fit - } - } - - // Which tick label should we start with? - function SetTextLabelStart($aTextLabelOff) { - $this->text_label_start=$aTextLabelOff; - } - -} // Class - -//=================================================== -// CLASS LinearScale -// Description: Handle linear scaling between screen and world -//=================================================== -class LinearScale { - public $textscale=false; // Just a flag to let the Plot class find out if - // we are a textscale or not. This is a cludge since - // this information is available in Graph::axtype but - // we don't have access to the graph object in the Plots - // stroke method. So we let graph store the status here - // when the linear scale is created. A real cludge... - public $type; // is this x or y scale ? - public $ticks=null; // Store ticks - public $text_scale_off = 0; - public $scale_abs=array(0,0); - public $scale_factor; // Scale factor between world and screen - public $off; // Offset between image edge and plot area - public $scale=array(0,0); - public $name = 'lin'; - public $auto_ticks=false; // When using manual scale should the ticks be automatically set? - public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php) - public $world_size; // Plot area size in world coordinates - public $intscale=false; // Restrict autoscale to integers - protected $autoscale_min=false; // Forced minimum value, auto determine max - protected $autoscale_max=false; // Forced maximum value, auto determine min - private $gracetop=0,$gracebottom=0; - - function __construct($aMin=0,$aMax=0,$aType='y') { - assert($aType=='x' || $aType=='y' ); - assert($aMin<=$aMax); - - $this->type=$aType; - $this->scale=array($aMin,$aMax); - $this->world_size=$aMax-$aMin; - $this->ticks = new LinearTicks(); - } - - // Check if scale is set or if we should autoscale - // We should do this is either scale or ticks has not been set - function IsSpecified() { - if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set - return false; - } - return true; - } - - // Set the minimum data value when the autoscaling is used. - // Usefull if you want a fix minimum (like 0) but have an - // automatic maximum - function SetAutoMin($aMin) { - $this->autoscale_min=$aMin; - } - - // Set the minimum data value when the autoscaling is used. - // Usefull if you want a fix minimum (like 0) but have an - // automatic maximum - function SetAutoMax($aMax) { - $this->autoscale_max=$aMax; - } - - // If the user manually specifies a scale should the ticks - // still be set automatically? - function SetAutoTicks($aFlag=true) { - $this->auto_ticks = $aFlag; - } - - // Specify scale "grace" value (top and bottom) - function SetGrace($aGraceTop,$aGraceBottom=0) { - if( $aGraceTop<0 || $aGraceBottom < 0 ) { - JpGraphError::RaiseL(25069);//(" Grace must be larger then 0"); - } - $this->gracetop=$aGraceTop; - $this->gracebottom=$aGraceBottom; - } - - // Get the minimum value in the scale - function GetMinVal() { - return $this->scale[0]; - } - - // get maximum value for scale - function GetMaxVal() { - return $this->scale[1]; - } - - // Specify a new min/max value for sclae - function Update($aImg,$aMin,$aMax) { - $this->scale=array($aMin,$aMax); - $this->world_size=$aMax-$aMin; - $this->InitConstants($aImg); - } - - // Translate between world and screen - function Translate($aCoord) { - if( !is_numeric($aCoord) ) { - if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) { - JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); - } - return 0; - } - else { - return round($this->off+($aCoord - $this->scale[0]) * $this->scale_factor); - } - } - - // Relative translate (don't include offset) usefull when we just want - // to know the relative position (in pixels) on the axis - function RelTranslate($aCoord) { - if( !is_numeric($aCoord) ) { - if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) { - JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); - } - return 0; - } - else { - return ($aCoord - $this->scale[0]) * $this->scale_factor; - } - } - - // Restrict autoscaling to only use integers - function SetIntScale($aIntScale=true) { - $this->intscale=$aIntScale; - } - - // Calculate an integer autoscale - function IntAutoScale($img,$min,$max,$maxsteps,$majend=true) { - // Make sure limits are integers - $min=floor($min); - $max=ceil($max); - if( abs($min-$max)==0 ) { - --$min; ++$max; - } - $maxsteps = floor($maxsteps); - - $gracetop=round(($this->gracetop/100.0)*abs($max-$min)); - $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min)); - if( is_numeric($this->autoscale_min) ) { - $min = ceil($this->autoscale_min); - if( $min >= $max ) { - JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); - } - } - - if( is_numeric($this->autoscale_max) ) { - $max = ceil($this->autoscale_max); - if( $min >= $max ) { - JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); - } - } - - if( abs($min-$max ) == 0 ) { - ++$max; - --$min; - } - - $min -= $gracebottom; - $max += $gracetop; - - // First get tickmarks as multiples of 1, 10, ... - if( $majend ) { - list($num1steps,$adj1min,$adj1max,$maj1step) = $this->IntCalcTicks($maxsteps,$min,$max,1); - } - else { - $adj1min = $min; - $adj1max = $max; - list($num1steps,$maj1step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,1); - } - - if( abs($min-$max) > 2 ) { - // Then get tick marks as 2:s 2, 20, ... - if( $majend ) { - list($num2steps,$adj2min,$adj2max,$maj2step) = $this->IntCalcTicks($maxsteps,$min,$max,5); - } - else { - $adj2min = $min; - $adj2max = $max; - list($num2steps,$maj2step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,5); - } - } - else { - $num2steps = 10000; // Dummy high value so we don't choose this - } - - if( abs($min-$max) > 5 ) { - // Then get tickmarks as 5:s 5, 50, 500, ... - if( $majend ) { - list($num5steps,$adj5min,$adj5max,$maj5step) = $this->IntCalcTicks($maxsteps,$min,$max,2); - } - else { - $adj5min = $min; - $adj5max = $max; - list($num5steps,$maj5step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,2); - } - } - else { - $num5steps = 10000; // Dummy high value so we don't choose this - } - - // Check to see whichof 1:s, 2:s or 5:s fit better with - // the requested number of major ticks - $match1=abs($num1steps-$maxsteps); - $match2=abs($num2steps-$maxsteps); - if( !empty($maj5step) && $maj5step > 1 ) { - $match5=abs($num5steps-$maxsteps); - } - else { - $match5=10000; // Dummy high value - } - - // Compare these three values and see which is the closest match - // We use a 0.6 weight to gravitate towards multiple of 5:s - if( $match1 < $match2 ) { - if( $match1 < $match5 ) $r=1; - else $r=3; - } - else { - if( $match2 < $match5 ) $r=2; - else $r=3; - } - // Minsteps are always the same as maxsteps for integer scale - switch( $r ) { - case 1: - $this->ticks->Set($maj1step,$maj1step); - $this->Update($img,$adj1min,$adj1max); - break; - case 2: - $this->ticks->Set($maj2step,$maj2step); - $this->Update($img,$adj2min,$adj2max); - break; - case 3: - $this->ticks->Set($maj5step,$maj5step); - $this->Update($img,$adj5min,$adj5max); - break; - default: - JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)'); - } - } - - - // Calculate autoscale. Used if user hasn't given a scale and ticks - // $maxsteps is the maximum number of major tickmarks allowed. - function AutoScale($img,$min,$max,$maxsteps,$majend=true) { - - if( !is_numeric($min) || !is_numeric($max) ) { - JpGraphError::Raise(25044); - } - - if( $this->intscale ) { - $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); - return; - } - if( abs($min-$max) < 0.00001 ) { - // We need some difference to be able to autoscale - // make it 5% above and 5% below value - if( $min==0 && $max==0 ) { // Special case - $min=-1; $max=1; - } - else { - $delta = (abs($max)+abs($min))*0.005; - $min -= $delta; - $max += $delta; - } - } - - $gracetop=($this->gracetop/100.0)*abs($max-$min); - $gracebottom=($this->gracebottom/100.0)*abs($max-$min); - if( is_numeric($this->autoscale_min) ) { - $min = $this->autoscale_min; - if( $min >= $max ) { - JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); - } - if( abs($min-$max ) < 0.001 ) { - $max *= 1.2; - } - } - - if( is_numeric($this->autoscale_max) ) { - $max = $this->autoscale_max; - if( $min >= $max ) { - JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); - } - if( abs($min-$max ) < 0.001 ) { - $min *= 0.8; - } - } - - $min -= $gracebottom; - $max += $gracetop; - - // First get tickmarks as multiples of 0.1, 1, 10, ... - if( $majend ) { - list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = $this->CalcTicks($maxsteps,$min,$max,1,2); - } - else { - $adj1min=$min; - $adj1max=$max; - list($num1steps,$min1step,$maj1step) = $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false); - } - - // Then get tick marks as 2:s 0.2, 2, 20, ... - if( $majend ) { - list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = $this->CalcTicks($maxsteps,$min,$max,5,2); - } - else { - $adj2min=$min; - $adj2max=$max; - list($num2steps,$min2step,$maj2step) = $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false); - } - - // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... - if( $majend ) { - list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = $this->CalcTicks($maxsteps,$min,$max,2,5); - } - else { - $adj5min=$min; - $adj5max=$max; - list($num5steps,$min5step,$maj5step) = $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false); - } - - // Check to see whichof 1:s, 2:s or 5:s fit better with - // the requested number of major ticks - $match1=abs($num1steps-$maxsteps); - $match2=abs($num2steps-$maxsteps); - $match5=abs($num5steps-$maxsteps); - - // Compare these three values and see which is the closest match - // We use a 0.8 weight to gravitate towards multiple of 5:s - $r=$this->MatchMin3($match1,$match2,$match5,0.8); - switch( $r ) { - case 1: - $this->Update($img,$adj1min,$adj1max); - $this->ticks->Set($maj1step,$min1step); - break; - case 2: - $this->Update($img,$adj2min,$adj2max); - $this->ticks->Set($maj2step,$min2step); - break; - case 3: - $this->Update($img,$adj5min,$adj5max); - $this->ticks->Set($maj5step,$min5step); - break; - } - } - - //--------------- - // PRIVATE METHODS - - // This method recalculates all constants that are depending on the - // margins in the image. If the margins in the image are changed - // this method should be called for every scale that is registred with - // that image. Should really be installed as an observer of that image. - function InitConstants($img) { - if( $this->type=='x' ) { - $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; - $this->off=$img->left_margin; - $this->scale_factor = 0; - if( $this->world_size > 0 ) { - $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); - } - } - else { // y scale - $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; - $this->off=$img->top_margin+$this->world_abs_size; - $this->scale_factor = 0; - if( $this->world_size > 0 ) { - $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0); - } - } - $size = $this->world_size * $this->scale_factor; - $this->scale_abs=array($this->off,$this->off + $size); - } - - // Initialize the conversion constants for this scale - // This tries to pre-calculate as much as possible to speed up the - // actual conversion (with Translate()) later on - // $start =scale start in absolute pixels (for x-scale this is an y-position - // and for an y-scale this is an x-position - // $len =absolute length in pixels of scale - function SetConstants($aStart,$aLen) { - $this->world_abs_size=$aLen; - $this->off=$aStart; - - if( $this->world_size<=0 ) { - // This should never ever happen !! - JpGraphError::RaiseL(25074); - //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale]
      Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); - } - - // scale_factor = number of pixels per world unit - $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); - - // scale_abs = start and end points of scale in absolute pixels - $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); - } - - - // Calculate number of ticks steps with a specific division - // $a is the divisor of 10**x to generate the first maj tick intervall - // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,... - // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,... - // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,... - // We return a vector of - // [$numsteps,$adjmin,$adjmax,$minstep,$majstep] - // If $majend==true then the first and last marks on the axis will be major - // labeled tick marks otherwise it will be adjusted to the closest min tick mark - function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) { - $diff=$max-$min; - if( $diff==0 ) { - $ld=0; - } - else { - $ld=floor(log10($diff)); - } - - // Gravitate min towards zero if we are close - if( $min>0 && $min < pow(10,$ld) ) $min=0; - - //$majstep=pow(10,$ld-1)/$a; - $majstep=pow(10,$ld)/$a; - $minstep=$majstep/$b; - - $adjmax=ceil($max/$minstep)*$minstep; - $adjmin=floor($min/$minstep)*$minstep; - $adjdiff = $adjmax-$adjmin; - $numsteps=$adjdiff/$majstep; - - while( $numsteps>$maxsteps ) { - $majstep=pow(10,$ld)/$a; - $numsteps=$adjdiff/$majstep; - ++$ld; - } - - $minstep=$majstep/$b; - $adjmin=floor($min/$minstep)*$minstep; - $adjdiff = $adjmax-$adjmin; - if( $majend ) { - $adjmin = floor($min/$majstep)*$majstep; - $adjdiff = $adjmax-$adjmin; - $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; - } - else { - $adjmax=ceil($max/$minstep)*$minstep; - } - - return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); - } - - function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) { - // Same as CalcTicks but don't adjust min/max values - $diff=$max-$min; - if( $diff==0 ) { - $ld=0; - } - else { - $ld=floor(log10($diff)); - } - - //$majstep=pow(10,$ld-1)/$a; - $majstep=pow(10,$ld)/$a; - $minstep=$majstep/$b; - $numsteps=floor($diff/$majstep); - - while( $numsteps > $maxsteps ) { - $majstep=pow(10,$ld)/$a; - $numsteps=floor($diff/$majstep); - ++$ld; - } - $minstep=$majstep/$b; - return array($numsteps,$minstep,$majstep); - } - - - function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) { - $diff=$max-$min; - if( $diff==0 ) { - JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); - } - else { - $ld=floor(log10($diff)); - } - - // Gravitate min towards zero if we are close - if( $min>0 && $min < pow(10,$ld) ) { - $min=0; - } - if( $ld == 0 ) { - $ld=1; - } - if( $a == 1 ) { - $majstep = 1; - } - else { - $majstep=pow(10,$ld)/$a; - } - $adjmax=ceil($max/$majstep)*$majstep; - - $adjmin=floor($min/$majstep)*$majstep; - $adjdiff = $adjmax-$adjmin; - $numsteps=$adjdiff/$majstep; - while( $numsteps>$maxsteps ) { - $majstep=pow(10,$ld)/$a; - $numsteps=$adjdiff/$majstep; - ++$ld; - } - - $adjmin=floor($min/$majstep)*$majstep; - $adjdiff = $adjmax-$adjmin; - if( $majend ) { - $adjmin = floor($min/$majstep)*$majstep; - $adjdiff = $adjmax-$adjmin; - $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; - } - else { - $adjmax=ceil($max/$majstep)*$majstep; - } - - return array($numsteps,$adjmin,$adjmax,$majstep); - } - - - function IntCalcTicksFreeze($maxsteps,$min,$max,$a) { - // Same as IntCalcTick but don't change min/max values - $diff=$max-$min; - if( $diff==0 ) { - JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); - } - else { - $ld=floor(log10($diff)); - } - if( $ld == 0 ) { - $ld=1; - } - if( $a == 1 ) { - $majstep = 1; - } - else { - $majstep=pow(10,$ld)/$a; - } - - $numsteps=floor($diff/$majstep); - while( $numsteps > $maxsteps ) { - $majstep=pow(10,$ld)/$a; - $numsteps=floor($diff/$majstep); - ++$ld; - } - - return array($numsteps,$majstep); - } - - // Determine the minimum of three values witha weight for last value - function MatchMin3($a,$b,$c,$weight) { - if( $a < $b ) { - if( $a < ($c*$weight) ) { - return 1; // $a smallest - } - else { - return 3; // $c smallest - } - } - elseif( $b < ($c*$weight) ) { - return 2; // $b smallest - } - return 3; // $c smallest - } -} // Class - - -//=================================================== -// CLASS DisplayValue -// Description: Used to print data values at data points -//=================================================== -class DisplayValue { - public $margin=5; - public $show=false; - public $valign='',$halign='center'; - public $format='%.1f',$negformat=''; - private $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10; - private $iFormCallback=''; - private $angle=0; - private $color='navy',$negcolor=''; - private $iHideZero=false; - public $txt=null; - - function __construct() { - $this->txt = new Text(); - } - - function Show($aFlag=true) { - $this->show=$aFlag; - } - - function SetColor($aColor,$aNegcolor='') { - $this->color = $aColor; - $this->negcolor = $aNegcolor; - } - - function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { - $this->ff=$aFontFamily; - $this->fs=$aFontStyle; - $this->fsize=$aFontSize; - } - - function ApplyFont($aImg) { - $aImg->SetFont($this->ff,$this->fs,$this->fsize); - } - - function SetMargin($aMargin) { - $this->margin = $aMargin; - } - - function SetAngle($aAngle) { - $this->angle = $aAngle; - } - - function SetAlign($aHAlign,$aVAlign='') { - $this->halign = $aHAlign; - $this->valign = $aVAlign; - } - - function SetFormat($aFormat,$aNegFormat='') { - $this->format= $aFormat; - $this->negformat= $aNegFormat; - } - - function SetFormatCallback($aFunc) { - $this->iFormCallback = $aFunc; - } - - function HideZero($aFlag=true) { - $this->iHideZero=$aFlag; - } - - function Stroke($img,$aVal,$x,$y) { - - if( $this->show ) - { - if( $this->negformat=='' ) { - $this->negformat=$this->format; - } - if( $this->negcolor=='' ) { - $this->negcolor=$this->color; - } - - if( $aVal===NULL || (is_string($aVal) && ($aVal=='' || $aVal=='-' || $aVal=='x' ) ) ) { - return; - } - - if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) { - return; - } - - // Since the value is used in different cirumstances we need to check what - // kind of formatting we shall use. For example, to display values in a line - // graph we simply display the formatted value, but in the case where the user - // has already specified a text string we don't fo anything. - if( $this->iFormCallback != '' ) { - $f = $this->iFormCallback; - $sval = call_user_func($f,$aVal); - } - elseif( is_numeric($aVal) ) { - if( $aVal >= 0 ) { - $sval=sprintf($this->format,$aVal); - } - else { - $sval=sprintf($this->negformat,$aVal); - } - } - else { - $sval=$aVal; - } - - $y = $y-sign($aVal)*$this->margin; - - $this->txt->Set($sval); - $this->txt->SetPos($x,$y); - $this->txt->SetFont($this->ff,$this->fs,$this->fsize); - if( $this->valign == '' ) { - if( $aVal >= 0 ) { - $valign = "bottom"; - } - else { - $valign = "top"; - } - } - else { - $valign = $this->valign; - } - $this->txt->Align($this->halign,$valign); - - $this->txt->SetOrientation($this->angle); - if( $aVal > 0 ) { - $this->txt->SetColor($this->color); - } - else { - $this->txt->SetColor($this->negcolor); - } - $this->txt->Stroke($img); - } - } -} - -//=================================================== -// CLASS Plot -// Description: Abstract base class for all concrete plot classes -//=================================================== -class Plot { - public $numpoints=0; - public $value; - public $legend=''; - public $coords=array(); - public $color='black'; - public $hidelegend=false; - public $line_weight=1; - public $csimtargets=array(),$csimwintargets=array(); // Array of targets for CSIM - public $csimareas=''; // Resultant CSIM area tags - public $csimalts=null; // ALT:s for corresponding target - public $legendcsimtarget='',$legendcsimwintarget=''; - public $legendcsimalt=''; - protected $weight=1; - protected $center=false; - - function __construct($aDatay,$aDatax=false) { - $this->numpoints = count($aDatay); - if( $this->numpoints==0 ) { - JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); - } - $this->coords[0]=$aDatay; - if( is_array($aDatax) ) { - $this->coords[1]=$aDatax; - $n = count($aDatax); - for( $i=0; $i < $n; ++$i ) { - if( !is_numeric($aDatax[$i]) ) { - JpGraphError::RaiseL(25070); - } - } - } - $this->value = new DisplayValue(); - } - - // Stroke the plot - // "virtual" function which must be implemented by - // the subclasses - function Stroke($aImg,$aXScale,$aYScale) { - JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot"); - } - - function HideLegend($f=true) { - $this->hidelegend = $f; - } - - function DoLegend($graph) { - if( !$this->hidelegend ) - $this->Legend($graph); - } - - function StrokeDataValue($img,$aVal,$x,$y) { - $this->value->Stroke($img,$aVal,$x,$y); - } - - // Set href targets for CSIM - function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { - $this->csimtargets=$aTargets; - $this->csimwintargets=$aWinTargets; - $this->csimalts=$aAlts; - } - - // Get all created areas - function GetCSIMareas() { - return $this->csimareas; - } - - // "Virtual" function which gets called before any scale - // or axis are stroked used to do any plot specific adjustment - function PreStrokeAdjust($aGraph) { - if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) { - JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); - } - return true; - } - - // Virtual function to the the concrete plot class to make any changes to the graph - // and scale before the stroke process begins - function PreScaleSetup($aGraph) { - // Empty - } - - // Get minimum values in plot - function Min() { - if( isset($this->coords[1]) ) { - $x=$this->coords[1]; - } - else { - $x=''; - } - if( $x != '' && count($x) > 0 ) { - $xm=min($x); - } - else { - $xm=0; - } - $y=$this->coords[0]; - $cnt = count($y); - if( $cnt > 0 ) { - $i=0; - while( $i<$cnt && !is_numeric($ym=$y[$i]) ) { - $i++; - } - while( $i < $cnt) { - if( is_numeric($y[$i]) ) { - $ym=min($ym,$y[$i]); - } - ++$i; - } - } - else { - $ym=''; - } - return array($xm,$ym); - } - - // Get maximum value in plot - function Max() { - if( isset($this->coords[1]) ) { - $x=$this->coords[1]; - } - else { - $x=''; - } - - if( $x!='' && count($x) > 0 ) { - $xm=max($x); - } - else { - $xm = $this->numpoints-1; - } - $y=$this->coords[0]; - if( count($y) > 0 ) { - $cnt = count($y); - $i=0; - while( $i<$cnt && !is_numeric($ym=$y[$i]) ) { - $i++; - } - while( $i < $cnt ) { - if( is_numeric($y[$i]) ) { - $ym=max($ym,$y[$i]); - } - ++$i; - } - } - else { - $ym=''; - } - return array($xm,$ym); - } - - function SetColor($aColor) { - $this->color=$aColor; - } - - function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { - $this->legend = $aLegend; - $this->legendcsimtarget = $aCSIM; - $this->legendcsimwintarget = $aCSIMWinTarget; - $this->legendcsimalt = $aCSIMAlt; - } - - function SetWeight($aWeight) { - $this->weight=$aWeight; - } - - function SetLineWeight($aWeight=1) { - $this->line_weight=$aWeight; - } - - function SetCenter($aCenter=true) { - $this->center = $aCenter; - } - - // This method gets called by Graph class to plot anything that should go - // into the margin after the margin color has been set. - function StrokeMargin($aImg) { - return true; - } - - // Framework function the chance for each plot class to set a legend - function Legend($aGraph) { - if( $this->legend != '' ) { - $aGraph->legend->Add($this->legend,$this->color,'',0,$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - } - -} // Class - - -// Provide a deterministic list of new colors whenever the getColor() method -// is called. Used to automatically set colors of plots. -class ColorFactory { - - static private $iIdx = 0; - static private $iColorList = array( - 'black', - 'blue', - 'orange', - 'darkgreen', - 'red', - 'AntiqueWhite3', - 'aquamarine3', - 'azure4', - 'brown', - 'cadetblue3', - 'chartreuse4', - 'chocolate', - 'darkblue', - 'darkgoldenrod3', - 'darkorchid3', - 'darksalmon', - 'darkseagreen4', - 'deepskyblue2', - 'dodgerblue4', - 'gold3', - 'hotpink', - 'lawngreen', - 'lightcoral', - 'lightpink3', - 'lightseagreen', - 'lightslateblue', - 'mediumpurple', - 'olivedrab', - 'orangered1', - 'peru', - 'slategray', - 'yellow4', - 'springgreen2'); - static private $iNum = 33; - - static function getColor() { - if( ColorFactory::$iIdx >= ColorFactory::$iNum ) - ColorFactory::$iIdx = 0; - return ColorFactory::$iColorList[ColorFactory::$iIdx++]; - } - -} - -// -?> +Get(11,$file,$lineno); + die($msg); + } + else { + define('CACHE_DIR', $_SERVER['TEMP'] . '/'); + } + } else { + define('CACHE_DIR','/tmp/jpgraph_cache/'); + } + } +} +elseif( !defined('CACHE_DIR') ) { + define('CACHE_DIR', ''); +} + +// +// Setup path for western/latin TTF fonts +// +if (!defined('TTF_DIR')) { + if (strstr( PHP_OS, 'WIN') ) { + $sroot = getenv('SystemRoot'); + if( empty($sroot) ) { + $t = new ErrMsgText(); + $msg = $t->Get(12,$file,$lineno); + die($msg); + } + else { + define('TTF_DIR', $sroot.'/fonts/'); + } + } else { + define('TTF_DIR','/usr/share/fonts/truetype/'); + } +} + +// +// Setup path for MultiByte TTF fonts (japanese, chinese etc.) +// +if (!defined('MBTTF_DIR')) { + if (strstr( PHP_OS, 'WIN') ) { + $sroot = getenv('SystemRoot'); + if( empty($sroot) ) { + $t = new ErrMsgText(); + $msg = $t->Get(12,$file,$lineno); + die($msg); + } + else { + define('MBTTF_DIR', $sroot.'/fonts/'); + } + } else { + define('MBTTF_DIR','/usr/share/fonts/truetype/'); + } +} + +// +// Check minimum PHP version +// +function CheckPHPVersion($aMinVersion) { + list($majorC, $minorC, $editC) = preg_split('/[\/.-]/', PHP_VERSION); + list($majorR, $minorR, $editR) = preg_split('/[\/.-]/', $aMinVersion); + + if ($majorC != $majorR) return false; + if ($majorC < $majorR) return false; + // same major - check minor + if ($minorC > $minorR) return true; + if ($minorC < $minorR) return false; + // and same minor + if ($editC >= $editR) return true; + return true; +} + +// +// Make sure PHP version is high enough +// +if( !CheckPHPVersion(MIN_PHPVERSION) ) { + JpGraphError::RaiseL(13,PHP_VERSION,MIN_PHPVERSION); + die(); +} + +// +// Make GD sanity check +// +if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) { + JpGraphError::RaiseL(25001); + //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)"); +} + +// +// Setup PHP error handler +// +function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) { + // Respect current error level + if( $errno & error_reporting() ) { + JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); + } +} + +if( INSTALL_PHP_ERR_HANDLER ) { + set_error_handler("_phpErrorHandler"); +} + +// +// Check if there were any warnings, perhaps some wrong includes by the user. In this +// case we raise it immediately since otherwise the image will not show and makes +// debugging difficult. This is controlled by the user setting CATCH_PHPERRMSG +// +if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) { + JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']); +} + +// Useful mathematical function +function sign($a) {return $a >= 0 ? 1 : -1;} + +// +// Utility function to generate an image name based on the filename we +// are running from and assuming we use auto detection of graphic format +// (top level), i.e it is safe to call this function +// from a script that uses JpGraph +// +function GenImgName() { + // Determine what format we should use when we save the images + $supported = imagetypes(); + if( $supported & IMG_PNG ) $img_format="png"; + elseif( $supported & IMG_GIF ) $img_format="gif"; + elseif( $supported & IMG_JPG ) $img_format="jpeg"; + elseif( $supported & IMG_WBMP ) $img_format="wbmp"; + elseif( $supported & IMG_XPM ) $img_format="xpm"; + + + if( !isset($_SERVER['PHP_SELF']) ) { + JpGraphError::RaiseL(25005); + //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); + } + $fname = basename($_SERVER['PHP_SELF']); + if( !empty($_SERVER['QUERY_STRING']) ) { + $q = @$_SERVER['QUERY_STRING']; + $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format; + } + else { + $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format; + } + return $fname; +} + +//=================================================== +// CLASS JpgTimer +// Description: General timing utility class to handle +// time measurement of generating graphs. Multiple +// timers can be started. +//=================================================== +class JpgTimer { + private $start, $idx; + + function __construct() { + $this->idx=0; + } + + // Push a new timer start on stack + function Push() { + list($ms,$s)=explode(" ",microtime()); + $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; + } + + // Pop the latest timer start and return the diff with the + // current time + function Pop() { + assert($this->idx>0); + list($ms,$s)=explode(" ",microtime()); + $etime=floor($ms*1000) + (1000*$s); + $this->idx--; + return $etime-$this->start[$this->idx]; + } +} // Class + +//=================================================== +// CLASS DateLocale +// Description: Hold localized text used in dates +//=================================================== +class DateLocale { + + public $iLocale = 'C'; // environmental locale be used by default + private $iDayAbb = null, $iShortDay = null, $iShortMonth = null, $iMonthName = null; + + function __construct() { + settype($this->iDayAbb, 'array'); + settype($this->iShortDay, 'array'); + settype($this->iShortMonth, 'array'); + settype($this->iMonthName, 'array'); + $this->Set('C'); + } + + function Set($aLocale) { + if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ + $this->iLocale = $aLocale; + return TRUE; // already cached nothing else to do! + } + + $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME + + if (is_array($aLocale)) { + foreach ($aLocale as $loc) { + $res = @setlocale(LC_TIME, $loc); + if ( $res ) { + $aLocale = $loc; + break; + } + } + } + else { + $res = @setlocale(LC_TIME, $aLocale); + } + + if ( ! $res ) { + JpGraphError::RaiseL(25007,$aLocale); + //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region."); + return FALSE; + } + + $this->iLocale = $aLocale; + for( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ) { + $day = strftime('%a', strtotime("$ofs day")); + $day[0] = strtoupper($day[0]); + $this->iDayAbb[$aLocale][]= $day[0]; + $this->iShortDay[$aLocale][]= $day; + } + + for($i=1; $i<=12; ++$i) { + list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01"))); + $this->iShortMonth[$aLocale][] = ucfirst($short); + $this->iMonthName [$aLocale][] = ucfirst($full); + } + + setlocale(LC_TIME, $pLocale); + + return TRUE; + } + + + function GetDayAbb() { + return $this->iDayAbb[$this->iLocale]; + } + + function GetShortDay() { + return $this->iShortDay[$this->iLocale]; + } + + function GetShortMonth() { + return $this->iShortMonth[$this->iLocale]; + } + + function GetShortMonthName($aNbr) { + return $this->iShortMonth[$this->iLocale][$aNbr]; + } + + function GetLongMonthName($aNbr) { + return $this->iMonthName[$this->iLocale][$aNbr]; + } + + function GetMonth() { + return $this->iMonthName[$this->iLocale]; + } +} + +// Global object handlers +$gDateLocale = new DateLocale(); +$gJpgDateLocale = new DateLocale(); + +//======================================================= +// CLASS Footer +// Description: Encapsulates the footer line in the Graph +//======================================================= +class Footer { + public $iLeftMargin = 3, $iRightMargin = 3, $iBottomMargin = 3 ; + public $left,$center,$right; + private $iTimer=null, $itimerpoststring=''; + + function __construct() { + $this->left = new Text(); + $this->left->ParagraphAlign('left'); + $this->center = new Text(); + $this->center->ParagraphAlign('center'); + $this->right = new Text(); + $this->right->ParagraphAlign('right'); + } + + function SetTimer($aTimer,$aTimerPostString='') { + $this->iTimer = $aTimer; + $this->itimerpoststring = $aTimerPostString; + } + + function SetMargin($aLeft=3,$aRight=3,$aBottom=3) { + $this->iLeftMargin = $aLeft; + $this->iRightMargin = $aRight; + $this->iBottomMargin = $aBottom; + } + + function Stroke($aImg) { + $y = $aImg->height - $this->iBottomMargin; + $x = $this->iLeftMargin; + $this->left->Align('left','bottom'); + $this->left->Stroke($aImg,$x,$y); + + $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2; + $this->center->Align('center','bottom'); + $this->center->Stroke($aImg,$x,$y); + + $x = $aImg->width - $this->iRightMargin; + $this->right->Align('right','bottom'); + if( $this->iTimer != null ) { + $this->right->Set( $this->right->t . sprintf('%.3f',$this->iTimer->Pop()/1000.0) . $this->itimerpoststring ); + } + $this->right->Stroke($aImg,$x,$y); + } +} + + +//=================================================== +// CLASS Graph +// Description: Main class to handle graphs +//=================================================== +class Graph { + public $cache=null; // Cache object (singleton) + public $img=null; // Img object (singleton) + public $plots=array(); // Array of all plot object in the graph (for Y 1 axis) + public $y2plots=array(); // Array of all plot object in the graph (for Y 2 axis) + public $ynplots=array(); + public $xscale=null; // X Scale object (could be instance of LinearScale or LogScale + public $yscale=null,$y2scale=null, $ynscale=array(); + public $iIcons = array(); // Array of Icons to add to + public $cache_name; // File name to be used for the current graph in the cache directory + public $xgrid=null; // X Grid object (linear or logarithmic) + public $ygrid=null,$y2grid=null; //dito for Y + public $doframe=true,$frame_color='black', $frame_weight=1; // Frame around graph + public $boxed=false, $box_color='black', $box_weight=1; // Box around plot area + public $doshadow=false,$shadow_width=4,$shadow_color='gray@0.5'; // Shadow for graph + public $xaxis=null; // X-axis (instane of Axis class) + public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class) + public $margin_color=array(230,230,230); // Margin color of graph + public $plotarea_color=array(255,255,255); // Plot area color + public $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object + public $axtype="linlin"; // Type of axis + public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width + public $texts=null, $y2texts=null; // Text object to ge shown in the graph + public $lines=null, $y2lines=null; + public $bands=null, $y2bands=null; + public $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale in fractions and for centering bars + public $background_image='',$background_image_type=-1,$background_image_format="png"; + public $background_image_bright=0,$background_image_contr=0,$background_image_sat=0; + public $background_image_xpos=0,$background_image_ypos=0; + public $image_bright=0, $image_contr=0, $image_sat=0; + public $inline; + public $showcsim=0,$csimcolor="red";//debug stuff, draw the csim boundaris on the image if <>0 + public $grid_depth=DEPTH_BACK; // Draw grid under all plots as default + public $iAxisStyle = AXSTYLE_SIMPLE; + public $iCSIMdisplay=false,$iHasStroked = false; + public $footer; + public $csimcachename = '', $csimcachetimeout = 0, $iCSIMImgAlt=''; + public $iDoClipping = false; + public $y2orderback=true; + public $tabtitle; + public $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN; + public $bkg_gradfrom='navy', $bkg_gradto='silver'; + public $plot_gradtype=-1,$plot_gradstyle=BGRAD_MARGIN; + public $plot_gradfrom='silver', $plot_gradto='navy'; + + public $titlebackground = false; + public $titlebackground_color = 'lightblue', + $titlebackground_style = 1, + $titlebackground_framecolor = 'blue', + $titlebackground_framestyle = 2, + $titlebackground_frameweight = 1, + $titlebackground_bevelheight = 3 ; + public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; + public $titlebkg_scolor1='black',$titlebkg_scolor2='white'; + public $framebevel = false, $framebeveldepth = 2 ; + public $framebevelborder = false, $framebevelbordercolor='black'; + public $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4'; + public $background_image_mix=100; + public $background_cflag = ''; + public $background_cflag_type = BGIMG_FILLPLOT; + public $background_cflag_mix = 100; + public $iImgTrans=false, + $iImgTransHorizon = 100,$iImgTransSkewDist=150, + $iImgTransDirection = 1, $iImgTransMinSize = true, + $iImgTransFillColor='white',$iImgTransHighQ=false, + $iImgTransBorder=false,$iImgTransHorizonPos=0.5; + public $legend; + protected $iYAxisDeltaPos=50; + protected $iIconDepth=DEPTH_BACK; + protected $iAxisLblBgType = 0, + $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black', + $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black'; + protected $iTables=NULL; + + // aWIdth Width in pixels of image + // aHeight Height in pixels of image + // aCachedName Name for image file in cache directory + // aTimeOut Timeout in minutes for image in cache + // aInline If true the image is streamed back in the call to Stroke() + // If false the image is just created in the cache + function __construct($aWidth=300,$aHeight=200,$aCachedName='',$aTimeout=0,$aInline=true) { + + if( !is_numeric($aWidth) || !is_numeric($aHeight) ) { + JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); + } + + // Automatically generate the image file name based on the name of the script that + // generates the graph + if( $aCachedName == 'auto' ) { + $aCachedName=GenImgName(); + } + + // Should the image be streamed back to the browser or only to the cache? + $this->inline=$aInline; + + $this->img = new RotImage($aWidth,$aHeight); + $this->cache = new ImgStreamCache(); + + // Window doesn't like '?' in the file name so replace it with an '_' + $aCachedName = str_replace("?","_",$aCachedName); + $this->SetupCache($aCachedName, $aTimeout); + + $this->title = new Text(); + $this->title->ParagraphAlign('center'); + $this->title->SetFont(FF_FONT2,FS_BOLD); + $this->title->SetMargin(5); + $this->title->SetAlign('center'); + + $this->subtitle = new Text(); + $this->subtitle->ParagraphAlign('center'); + $this->subtitle->SetMargin(3); + $this->subtitle->SetAlign('center'); + + $this->subsubtitle = new Text(); + $this->subsubtitle->ParagraphAlign('center'); + $this->subsubtitle->SetMargin(3); + $this->subsubtitle->SetAlign('center'); + + $this->legend = new Legend(); + $this->footer = new Footer(); + + // If the cached version exist just read it directly from the + // cache, stream it back to browser and exit + if( $aCachedName!='' && READ_CACHE && $aInline ) { + if( $this->cache->GetAndStream($this->img,$aCachedName) ) { + exit(); + } + } + + $this->SetTickDensity(); // Normal density + + $this->tabtitle = new GraphTabTitle(); + } + + function SetupCache($aFilename,$aTimeout=60) { + $this->cache_name = $aFilename; + $this->cache->SetTimeOut($aTimeout); + } + + // Enable final image perspective transformation + function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) { + $this->iImgTrans = true; + $this->iImgTransHorizon = $aHorizon; + $this->iImgTransSkewDist= $aSkewDist; + $this->iImgTransDirection = $aDir; + $this->iImgTransMinSize = $aMinSize; + $this->iImgTransFillColor=$aFillColor; + $this->iImgTransHighQ=$aQuality; + $this->iImgTransBorder=$aBorder; + $this->iImgTransHorizonPos=$aHorizonPos; + } + + function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->img->ttf->SetUserFont($aNormal,$aBold,$aItalic,$aBoldIt); + } + + function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->img->ttf->SetUserFont1($aNormal,$aBold,$aItalic,$aBoldIt); + } + + function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->img->ttf->SetUserFont2($aNormal,$aBold,$aItalic,$aBoldIt); + } + + function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->img->ttf->SetUserFont3($aNormal,$aBold,$aItalic,$aBoldIt); + } + + // Set Image format and optional quality + function SetImgFormat($aFormat,$aQuality=75) { + $this->img->SetImgFormat($aFormat,$aQuality); + } + + // Should the grid be in front or back of the plot? + function SetGridDepth($aDepth) { + $this->grid_depth=$aDepth; + } + + function SetIconDepth($aDepth) { + $this->iIconDepth=$aDepth; + } + + // Specify graph angle 0-360 degrees. + function SetAngle($aAngle) { + $this->img->SetAngle($aAngle); + } + + function SetAlphaBlending($aFlg=true) { + $this->img->SetAlphaBlending($aFlg); + } + + // Shortcut to image margin + function SetMargin($lm,$rm,$tm,$bm) { + $this->img->SetMargin($lm,$rm,$tm,$bm); + } + + function SetY2OrderBack($aBack=true) { + $this->y2orderback = $aBack; + } + + // Rotate the graph 90 degrees and set the margin + // when we have done a 90 degree rotation + function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { + $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ; + $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ; + $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ; + $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ; + + $adj = ($this->img->height - $this->img->width)/2; + $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj); + $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); + $this->SetAngle(90); + if( empty($this->yaxis) || empty($this->xaxis) ) { + JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()'); + } + $this->xaxis->SetLabelAlign('right','center'); + $this->yaxis->SetLabelAlign('center','bottom'); + } + + function SetClipping($aFlg=true) { + $this->iDoClipping = $aFlg ; + } + + // Add a plot object to the graph + function Add($aPlot) { + if( $aPlot == null ) { + JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); + } + if( is_array($aPlot) && count($aPlot) > 0 ) { + $cl = $aPlot[0]; + } + else { + $cl = $aPlot; + } + + if( $cl instanceof Text ) $this->AddText($aPlot); + elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) $this->AddLine($aPlot); + elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) $this->AddBand($aPlot); + elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot); + elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) $this->AddTable($aPlot); + else { + if( is_array($aPlot) ) { + $this->plots = array_merge($this->plots,$aPlot); + } + else { + $this->plots[] = $aPlot; + } + } + } + + function AddTable($aTable) { + if( is_array($aTable) ) { + for($i=0; $i < count($aTable); ++$i ) { + $this->iTables[]=$aTable[$i]; + } + } + else { + $this->iTables[] = $aTable ; + } + } + + function AddIcon($aIcon) { + if( is_array($aIcon) ) { + for($i=0; $i < count($aIcon); ++$i ) { + $this->iIcons[]=$aIcon[$i]; + } + } + else { + $this->iIcons[] = $aIcon ; + } + } + + // Add plot to second Y-scale + function AddY2($aPlot) { + if( $aPlot == null ) { + JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph."); + } + + if( is_array($aPlot) && count($aPlot) > 0 ) { + $cl = $aPlot[0]; + } + else { + $cl = $aPlot; + } + + if( $cl instanceof Text ) { + $this->AddText($aPlot,true); + } + elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) { + $this->AddLine($aPlot,true); + } + elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) { + $this->AddBand($aPlot,true); + } + else { + $this->y2plots[] = $aPlot; + } + } + + // Add plot to the extra Y-axises + function AddY($aN,$aPlot) { + + if( $aPlot == null ) { + JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph."); + } + + if( is_array($aPlot) && count($aPlot) > 0 ) { + $cl = $aPlot[0]; + } + else { + $cl = $aPlot; + } + + if( ($cl instanceof Text) || + (class_exists('PlotLine',false) && ($cl instanceof PlotLine)) || + (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) { + JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis'); + } + else { + $this->ynplots[$aN][] = $aPlot; + } + } + + // Add text object to the graph + function AddText($aTxt,$aToY2=false) { + if( $aTxt == null ) { + JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph."); + } + if( $aToY2 ) { + if( is_array($aTxt) ) { + for($i=0; $i < count($aTxt); ++$i ) { + $this->y2texts[]=$aTxt[$i]; + } + } + else { + $this->y2texts[] = $aTxt; + } + } + else { + if( is_array($aTxt) ) { + for($i=0; $i < count($aTxt); ++$i ) { + $this->texts[]=$aTxt[$i]; + } + } + else { + $this->texts[] = $aTxt; + } + } + } + + // Add a line object (class PlotLine) to the graph + function AddLine($aLine,$aToY2=false) { + if( $aLine == null ) { + JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph."); + } + + if( $aToY2 ) { + if( is_array($aLine) ) { + for($i=0; $i < count($aLine); ++$i ) { + //$this->y2lines[]=$aLine[$i]; + $this->y2plots[]=$aLine[$i]; + } + } + else { + //$this->y2lines[] = $aLine; + $this->y2plots[]=$aLine; + } + } + else { + if( is_array($aLine) ) { + for($i=0; $ilines[]=$aLine[$i]; + $this->plots[]=$aLine[$i]; + } + } + else { + //$this->lines[] = $aLine; + $this->plots[] = $aLine; + } + } + } + + // Add vertical or horizontal band + function AddBand($aBand,$aToY2=false) { + if( $aBand == null ) { + JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph."); + } + + if( $aToY2 ) { + if( is_array($aBand) ) { + for($i=0; $i < count($aBand); ++$i ) { + $this->y2bands[] = $aBand[$i]; + } + } + else { + $this->y2bands[] = $aBand; + } + } + else { + if( is_array($aBand) ) { + for($i=0; $i < count($aBand); ++$i ) { + $this->bands[] = $aBand[$i]; + } + } + else { + $this->bands[] = $aBand; + } + } + } + + function SetPlotGradient($aFrom='navy',$aTo='silver',$aGradType=2) { + $this->plot_gradtype=$aGradType; + $this->plot_gradfrom = $aFrom; + $this->plot_gradto = $aTo; + } + + function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) { + $this->bkg_gradtype=$aGradType; + $this->bkg_gradstyle=$aStyle; + $this->bkg_gradfrom = $aFrom; + $this->bkg_gradto = $aTo; + } + + // Set a country flag in the background + function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { + $this->background_cflag = $aName; + $this->background_cflag_type = $aBgType; + $this->background_cflag_mix = $aMix; + } + + // Alias for the above method + function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { + $this->background_cflag = $aName; + $this->background_cflag_type = $aBgType; + $this->background_cflag_mix = $aMix; + } + + + // Specify a background image + function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat='auto') { + + // Get extension to determine image type + if( $aImgFormat == 'auto' ) { + $e = explode('.',$aFileName); + if( !$e ) { + JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); + } + + $valid_formats = array('png', 'jpg', 'gif'); + $aImgFormat = strtolower($e[count($e)-1]); + if ($aImgFormat == 'jpeg') { + $aImgFormat = 'jpg'; + } + elseif (!in_array($aImgFormat, $valid_formats) ) { + JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName); + } + } + + $this->background_image = $aFileName; + $this->background_image_type=$aBgType; + $this->background_image_format=$aImgFormat; + } + + function SetBackgroundImageMix($aMix) { + $this->background_image_mix = $aMix ; + } + + // Adjust background image position + function SetBackgroundImagePos($aXpos,$aYpos) { + $this->background_image_xpos = $aXpos ; + $this->background_image_ypos = $aYpos ; + } + + // Specify axis style (boxed or single) + function SetAxisStyle($aStyle) { + $this->iAxisStyle = $aStyle ; + } + + // Set a frame around the plot area + function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) { + $this->boxed = $aDrawPlotFrame; + $this->box_weight = $aPlotFrameWeight; + $this->box_color = $aPlotFrameColor; + } + + // Specify color for the plotarea (not the margins) + function SetColor($aColor) { + $this->plotarea_color=$aColor; + } + + // Specify color for the margins (all areas outside the plotarea) + function SetMarginColor($aColor) { + $this->margin_color=$aColor; + } + + // Set a frame around the entire image + function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) { + $this->doframe = $aDrawImgFrame; + $this->frame_color = $aImgFrameColor; + $this->frame_weight = $aImgFrameWeight; + } + + function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) { + $this->framebevel = $aFlg ; + $this->framebeveldepth = $aDepth ; + $this->framebevelborder = $aBorder ; + $this->framebevelbordercolor = $aBorderColor ; + $this->framebevelcolor1 = $aColor1 ; + $this->framebevelcolor2 = $aColor2 ; + + $this->doshadow = false ; + } + + // Set the shadow around the whole image + function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor='darkgray') { + $this->doshadow = $aShowShadow; + $this->shadow_color = $aShadowColor; + $this->shadow_width = $aShadowWidth; + $this->footer->iBottomMargin += $aShadowWidth; + $this->footer->iRightMargin += $aShadowWidth; + } + + // Specify x,y scale. Note that if you manually specify the scale + // you must also specify the tick distance with a call to Ticks::Set() + function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { + $this->axtype = $aAxisType; + + if( $aYMax < $aYMin || $aXMax < $aXMin ) { + JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.'); + } + + $yt=substr($aAxisType,-3,3); + if( $yt == 'lin' ) { + $this->yscale = new LinearScale($aYMin,$aYMax); + } + elseif( $yt == 'int' ) { + $this->yscale = new LinearScale($aYMin,$aYMax); + $this->yscale->SetIntScale(); + } + elseif( $yt == 'log' ) { + $this->yscale = new LogScale($aYMin,$aYMax); + } + else { + JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)"); + } + + $xt=substr($aAxisType,0,3); + if( $xt == 'lin' || $xt == 'tex' ) { + $this->xscale = new LinearScale($aXMin,$aXMax,'x'); + $this->xscale->textscale = ($xt == 'tex'); + } + elseif( $xt == 'int' ) { + $this->xscale = new LinearScale($aXMin,$aXMax,'x'); + $this->xscale->SetIntScale(); + } + elseif( $xt == 'dat' ) { + $this->xscale = new DateScale($aXMin,$aXMax,'x'); + } + elseif( $xt == 'log' ) { + $this->xscale = new LogScale($aXMin,$aXMax,'x'); + } + else { + JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)"); + } + + $this->xaxis = new Axis($this->img,$this->xscale); + $this->yaxis = new Axis($this->img,$this->yscale); + $this->xgrid = new Grid($this->xaxis); + $this->ygrid = new Grid($this->yaxis); + $this->ygrid->Show(); + } + + // Specify secondary Y scale + function SetY2Scale($aAxisType='lin',$aY2Min=1,$aY2Max=1) { + if( $aAxisType == 'lin' ) { + $this->y2scale = new LinearScale($aY2Min,$aY2Max); + } + elseif( $aAxisType == 'int' ) { + $this->y2scale = new LinearScale($aY2Min,$aY2Max); + $this->y2scale->SetIntScale(); + } + elseif( $aAxisType == 'log' ) { + $this->y2scale = new LogScale($aY2Min,$aY2Max); + } + else { + JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)"); + } + + $this->y2axis = new Axis($this->img,$this->y2scale); + $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); + $this->y2axis->SetLabelSide(SIDE_RIGHT); + $this->y2axis->SetPos('max'); + $this->y2axis->SetTitleSide(SIDE_RIGHT); + + // Deafult position is the max x-value + $this->y2grid = new Grid($this->y2axis); + } + + // Set the delta position (in pixels) between the multiple Y-axis + function SetYDeltaDist($aDist) { + $this->iYAxisDeltaPos = $aDist; + } + + // Specify secondary Y scale + function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) { + + if( $aAxisType == 'lin' ) { + $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); + } + elseif( $aAxisType == 'int' ) { + $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); + $this->ynscale[$aN]->SetIntScale(); + } + elseif( $aAxisType == 'log' ) { + $this->ynscale[$aN] = new LogScale($aYMin,$aYMax); + } + else { + JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)"); + } + + $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); + $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); + $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); + } + + // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' + // The dividing factor have been determined heuristically according to my aesthetic + // sense (or lack off) y.m.m.v ! + function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) { + $this->xtick_factor=30; + $this->ytick_factor=25; + switch( $aYDensity ) { + case TICKD_DENSE: + $this->ytick_factor=12; + break; + case TICKD_NORMAL: + $this->ytick_factor=25; + break; + case TICKD_SPARSE: + $this->ytick_factor=40; + break; + case TICKD_VERYSPARSE: + $this->ytick_factor=100; + break; + default: + JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy"); + } + switch( $aXDensity ) { + case TICKD_DENSE: + $this->xtick_factor=15; + break; + case TICKD_NORMAL: + $this->xtick_factor=30; + break; + case TICKD_SPARSE: + $this->xtick_factor=45; + break; + case TICKD_VERYSPARSE: + $this->xtick_factor=60; + break; + default: + JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx"); + } + } + + + // Get a string of all image map areas + function GetCSIMareas() { + if( !$this->iHasStroked ) { + $this->Stroke(_CSIM_SPECIALFILE); + } + + $csim = $this->title->GetCSIMAreas(); + $csim .= $this->subtitle->GetCSIMAreas(); + $csim .= $this->subsubtitle->GetCSIMAreas(); + $csim .= $this->legend->GetCSIMAreas(); + + if( $this->y2axis != NULL ) { + $csim .= $this->y2axis->title->GetCSIMAreas(); + } + + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i ) { + $csim .= $this->texts[$i]->GetCSIMAreas(); + } + } + + if( $this->y2texts != null && $this->y2scale != null ) { + $n = count($this->y2texts); + for($i=0; $i < $n; ++$i ) { + $csim .= $this->y2texts[$i]->GetCSIMAreas(); + } + } + + if( $this->yaxis != null && $this->xaxis != null ) { + $csim .= $this->yaxis->title->GetCSIMAreas(); + $csim .= $this->xaxis->title->GetCSIMAreas(); + } + + $n = count($this->plots); + for( $i=0; $i < $n; ++$i ) { + $csim .= $this->plots[$i]->GetCSIMareas(); + } + + $n = count($this->y2plots); + for( $i=0; $i < $n; ++$i ) { + $csim .= $this->y2plots[$i]->GetCSIMareas(); + } + + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + $m = count($this->ynplots[$i]); + for($j=0; $j < $m; ++$j ) { + $csim .= $this->ynplots[$i][$j]->GetCSIMareas(); + } + } + + $n = count($this->iTables); + for( $i=0; $i < $n; ++$i ) { + $csim .= $this->iTables[$i]->GetCSIMareas(); + } + + return $csim; + } + + // Get a complete .. tag for the final image map + function GetHTMLImageMap($aMapName) { + $im = "\n"; + $im .= $this->GetCSIMareas(); + $im .= ""; + return $im; + } + + function CheckCSIMCache($aCacheName,$aTimeOut=60) { + global $_SERVER; + + if( $aCacheName=='auto' ) { + $aCacheName=basename($_SERVER['PHP_SELF']); + } + + $urlarg = $this->GetURLArguments(); + $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg; + $this->csimcachetimeout = $aTimeOut; + + // First determine if we need to check for a cached version + // This differs from the standard cache in the sense that the + // image and CSIM map HTML file is written relative to the directory + // the script executes in and not the specified cache directory. + // The reason for this is that the cache directory is not necessarily + // accessible from the HTTP server. + if( $this->csimcachename != '' ) { + $dir = dirname($this->csimcachename); + $base = basename($this->csimcachename); + $base = strtok($base,'.'); + $suffix = strtok('.'); + $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; + $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format; + + $timedout=false; + // Does it exist at all ? + + if( file_exists($basecsim) && file_exists($baseimg) ) { + // Check that it hasn't timed out + $diff=time()-filemtime($basecsim); + if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) { + $timedout=true; + @unlink($basecsim); + @unlink($baseimg); + } + else { + if ($fh = @fopen($basecsim, "r")) { + fpassthru($fh); + return true; + } + else { + JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading."); + } + } + } + } + return false; + } + + // Build the argument string to be used with the csim images + static function GetURLArguments($aAddRecursiveBlocker=false) { + + if( $aAddRecursiveBlocker ) { + // This is a JPGRAPH internal defined that prevents + // us from recursively coming here again + $urlarg = _CSIM_DISPLAY.'=1'; + } + + // Now reconstruct any user URL argument + reset($_GET); + while( list($key,$value) = each($_GET) ) { + if( is_array($value) ) { + foreach ( $value as $k => $v ) { + $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); + } + } + else { + $urlarg .= '&'.$key.'='.urlencode($value); + } + } + + // It's not ideal to convert POST argument to GET arguments + // but there is little else we can do. One idea for the + // future might be recreate the POST header in case. + reset($_POST); + while( list($key,$value) = each($_POST) ) { + if( is_array($value) ) { + foreach ( $value as $k => $v ) { + $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); + } + } + else { + $urlarg .= '&'.$key.'='.urlencode($value); + } + } + + return $urlarg; + } + + function SetCSIMImgAlt($aAlt) { + $this->iCSIMImgAlt = $aAlt; + } + + function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) { + if( $aCSIMName=='' ) { + // create a random map name + srand ((double) microtime() * 1000000); + $r = rand(0,100000); + $aCSIMName='__mapname'.$r.'__'; + } + + if( $aScriptName=='auto' ) { + $aScriptName=basename($_SERVER['PHP_SELF']); + } + + $urlarg = $this->GetURLArguments(true); + + if( empty($_GET[_CSIM_DISPLAY]) ) { + // First determine if we need to check for a cached version + // This differs from the standard cache in the sense that the + // image and CSIM map HTML file is written relative to the directory + // the script executes in and not the specified cache directory. + // The reason for this is that the cache directory is not necessarily + // accessible from the HTTP server. + if( $this->csimcachename != '' ) { + $dir = dirname($this->csimcachename); + $base = basename($this->csimcachename); + $base = strtok($base,'.'); + $suffix = strtok('.'); + $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; + $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format; + + // Check that apache can write to directory specified + + if( file_exists($dir) && !is_writeable($dir) ) { + JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.'); + } + + // Make sure directory exists + $this->cache->MakeDirs($dir); + + // Write the image file + $this->Stroke(CSIMCACHE_DIR.$baseimg); + + // Construct wrapper HTML and write to file and send it back to browser + + // In the src URL we must replace the '?' with its encoding to prevent the arguments + // to be converted to real arguments. + $tmp = str_replace('?','%3f',$baseimg); + $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n". + 'img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n"; + + if($fh = @fopen($basecsim,'w') ) { + fwrite($fh,$htmlwrap); + fclose($fh); + echo $htmlwrap; + } + else { + JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions."); + } + } + else { + + if( $aScriptName=='' ) { + JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().'); + } + echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder); + } + } + else { + $this->Stroke(); + } + } + + function StrokeCSIMImage() { + if( @$_GET[_CSIM_DISPLAY] == 1 ) { + $this->Stroke(); + } + } + + function GetCSIMImgHTML($aCSIMName, $aScriptName='auto', $aBorder=0 ) { + if( $aScriptName=='auto' ) { + $aScriptName=basename($_SERVER['PHP_SELF']); + } + $urlarg = $this->GetURLArguments(true); + return "\"".$this-iCSIMImgAlt."\" />\n"; + } + + function GetTextsYMinMax($aY2=false) { + if( $aY2 ) { + $txts = $this->y2texts; + } + else { + $txts = $this->texts; + } + $n = count($txts); + $min=null; + $max=null; + for( $i=0; $i < $n; ++$i ) { + if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) { + if( $min === null ) { + $min = $max = $txts[$i]->iScalePosY ; + } + else { + $min = min($min,$txts[$i]->iScalePosY); + $max = max($max,$txts[$i]->iScalePosY); + } + } + } + if( $min !== null ) { + return array($min,$max); + } + else { + return null; + } + } + + function GetTextsXMinMax($aY2=false) { + if( $aY2 ) { + $txts = $this->y2texts; + } + else { + $txts = $this->texts; + } + $n = count($txts); + $min=null; + $max=null; + for( $i=0; $i < $n; ++$i ) { + if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) { + if( $min === null ) { + $min = $max = $txts[$i]->iScalePosX ; + } + else { + $min = min($min,$txts[$i]->iScalePosX); + $max = max($max,$txts[$i]->iScalePosX); + } + } + } + if( $min !== null ) { + return array($min,$max); + } + else { + return null; + } + } + + function GetXMinMax() { + + list($min,$ymin) = $this->plots[0]->Min(); + list($max,$ymax) = $this->plots[0]->Max(); + + $i=0; + // Some plots, e.g. PlotLine should not affect the scale + // and will return (null,null). We should ignore those + // values. + while( ($min===null || $max === null) && ($i < count($this->plots)-1) ) { + ++$i; + list($min,$ymin) = $this->plots[$i]->Min(); + list($max,$ymax) = $this->plots[$i]->Max(); + } + + foreach( $this->plots as $p ) { + list($xmin,$ymin) = $p->Min(); + list($xmax,$ymax) = $p->Max(); + + if( $xmin !== null && $xmax !== null ) { + $min = Min($xmin,$min); + $max = Max($xmax,$max); + } + } + + if( $this->y2axis != null ) { + foreach( $this->y2plots as $p ) { + list($xmin,$ymin) = $p->Min(); + list($xmax,$ymax) = $p->Max(); + $min = Min($xmin,$min); + $max = Max($xmax,$max); + } + } + + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + if( $this->ynaxis[$i] != null) { + foreach( $this->ynplots[$i] as $p ) { + list($xmin,$ymin) = $p->Min(); + list($xmax,$ymax) = $p->Max(); + $min = Min($xmin,$min); + $max = Max($xmax,$max); + } + } + } + return array($min,$max); + } + + function AdjustMarginsForTitles() { + $totrequired = ($this->title->t != '' ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) + + ($this->subtitle->t != '' ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + + ($this->subsubtitle->t != '' ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ; + + $btotrequired = 0; + if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { + // Minimum bottom margin + if( $this->xaxis->title->t != '' ) { + if( $this->img->a == 90 ) { + $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7 ; + } + else { + $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7 ; + } + } + else { + $btotrequired = 0; + } + + if( $this->img->a == 90 ) { + $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style, + $this->yaxis->font_size); + $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle); + } + else { + $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style, + $this->xaxis->font_size); + $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle); + } + + $btotrequired += $lh + 6; + } + + if( $this->img->a == 90 ) { + // DO Nothing. It gets too messy to do this properly for 90 deg... + } + else{ + if( $this->img->top_margin < $totrequired ) { + $this->SetMargin($this->img->left_margin,$this->img->right_margin, + $totrequired,$this->img->bottom_margin); + } + if( $this->img->bottom_margin < $btotrequired ) { + $this->SetMargin($this->img->left_margin,$this->img->right_margin, + $this->img->top_margin,$btotrequired); + } + } + } + + function StrokeStore($aStrokeFileName) { + // Get the handler to prevent the library from sending the + // image to the browser + $ih = $this->Stroke(_IMG_HANDLER); + + // Stroke it to a file + $this->img->Stream($aStrokeFileName); + + // Send it back to browser + $this->img->Headers(); + $this->img->Stream(); + } + + function doAutoscaleXAxis() { + //Check if we should autoscale x-axis + if( !$this->xscale->IsSpecified() ) { + if( substr($this->axtype,0,4) == "text" ) { + $max=0; + $n = count($this->plots); + for($i=0; $i < $n; ++$i ) { + $p = $this->plots[$i]; + // We need some unfortunate sub class knowledge here in order + // to increase number of data points in case it is a line plot + // which has the barcenter set. If not it could mean that the + // last point of the data is outside the scale since the barcenter + // settings means that we will shift the entire plot half a tick step + // to the right in oder to align with the center of the bars. + if( class_exists('BarPlot',false) ) { + $cl = strtolower(get_class($p)); + if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || empty($p->barcenter) ) { + $max=max($max,$p->numpoints-1); + } + else { + $max=max($max,$p->numpoints); + } + } + else { + if( empty($p->barcenter) ) { + $max=max($max,$p->numpoints-1); + } + else { + $max=max($max,$p->numpoints); + } + } + } + $min=0; + if( $this->y2axis != null ) { + foreach( $this->y2plots as $p ) { + $max=max($max,$p->numpoints-1); + } + } + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + if( $this->ynaxis[$i] != null) { + foreach( $this->ynplots[$i] as $p ) { + $max=max($max,$p->numpoints-1); + } + } + } + + $this->xscale->Update($this->img,$min,$max); + $this->xscale->ticks->Set($this->xaxis->tick_step,1); + $this->xscale->ticks->SupressMinorTickMarks(); + } + else { + list($min,$max) = $this->GetXMinMax(); + + $lres = $this->GetLinesXMinMax($this->lines); + if( $lres ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + + $lres = $this->GetLinesXMinMax($this->y2lines); + if( $lres ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + + $tres = $this->GetTextsXMinMax(); + if( $tres ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + + $tres = $this->GetTextsXMinMax(true); + if( $tres ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + + $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor)); + } + + //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale + if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) { + $this->yaxis->SetPos($this->xscale->GetMinVal()); + } + } + elseif( $this->xscale->IsSpecified() && + ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->xscale->scale[0]; + $max = $this->xscale->scale[1]; + $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor),false); + + // Now make sure we show enough precision to accurate display the + // labels. If this is not done then the user might end up with + // a scale that might actually start with, say 13.5, butdue to rounding + // the scale label will ony show 14. + if( abs(floor($min)-$min) > 0 ) { + + // If the user has set a format then we bail out + if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) { + $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; + } + } + } + + // Position the optional Y2 and Yn axis to the rightmost position of the x-axis + if( $this->y2axis != null ) { + if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) { + $this->y2axis->SetPos($this->xscale->GetMaxVal()); + } + $this->y2axis->SetTitleSide(SIDE_RIGHT); + } + + $n = count($this->ynaxis); + $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0; + for( $i=0; $i < $n; ++$i ) { + if( $this->ynaxis[$i] != null ) { + if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) { + $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal()); + $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj); + } + $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT); + } + } + } + + + function doAutoScaleYnAxis() { + + if( $this->y2scale != null) { + if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); + + $lres = $this->GetLinesYMinMax($this->y2lines); + if( is_array($lres) ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + $tres = $this->GetTextsYMinMax(true); + if( is_array($tres) ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); + } + elseif( $this->y2scale->IsSpecified() && ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->y2scale->scale[0]; + $max = $this->y2scale->scale[1]; + $this->y2scale->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor, + $this->y2scale->auto_ticks); + + // Now make sure we show enough precision to accurate display the + // labels. If this is not done then the user might end up with + // a scale that might actually start with, say 13.5, butdue to rounding + // the scale label will ony show 14. + if( abs(floor($min)-$min) > 0 ) { + // If the user has set a format then we bail out + if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) { + $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; + } + } + + } + } + + + // + // Autoscale the extra Y-axises + // + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + if( $this->ynscale[$i] != null) { + if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]); + $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); + } + elseif( $this->ynscale[$i]->IsSpecified() && ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->ynscale[$i]->scale[0]; + $max = $this->ynscale[$i]->scale[1]; + $this->ynscale[$i]->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor, + $this->ynscale[$i]->auto_ticks); + + // Now make sure we show enough precision to accurate display the + // labels. If this is not done then the user might end up with + // a scale that might actually start with, say 13.5, butdue to rounding + // the scale label will ony show 14. + if( abs(floor($min)-$min) > 0 ) { + // If the user has set a format then we bail out + if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) { + $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; + } + } + } + } + } + } + + function doAutoScaleYAxis() { + + //Check if we should autoscale y-axis + if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->plots); + $lres = $this->GetLinesYMinMax($this->lines); + if( is_array($lres) ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + $tres = $this->GetTextsYMinMax(); + if( is_array($tres) ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + $this->yscale->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor); + } + elseif( $this->yscale->IsSpecified() && ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->yscale->scale[0]; + $max = $this->yscale->scale[1]; + $this->yscale->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor, + $this->yscale->auto_ticks); + + // Now make sure we show enough precision to accurate display the + // labels. If this is not done then the user might end up with + // a scale that might actually start with, say 13.5, butdue to rounding + // the scale label will ony show 14. + if( abs(floor($min)-$min) > 0 ) { + + // If the user has set a format then we bail out + if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) { + $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; + } + } + } + + } + + function InitScaleConstants() { + // Setup scale constants + if( $this->yscale ) $this->yscale->InitConstants($this->img); + if( $this->xscale ) $this->xscale->InitConstants($this->img); + if( $this->y2scale ) $this->y2scale->InitConstants($this->img); + + $n=count($this->ynscale); + for($i=0; $i < $n; ++$i) { + if( $this->ynscale[$i] ) { + $this->ynscale[$i]->InitConstants($this->img); + } + } + } + + function doPrestrokeAdjustments() { + + // Do any pre-stroke adjustment that is needed by the different plot types + // (i.e bar plots want's to add an offset to the x-labels etc) + for($i=0; $i < count($this->plots) ; ++$i ) { + $this->plots[$i]->PreStrokeAdjust($this); + $this->plots[$i]->DoLegend($this); + } + + // Any plots on the second Y scale? + if( $this->y2scale != null ) { + for($i=0; $iy2plots) ; ++$i ) { + $this->y2plots[$i]->PreStrokeAdjust($this); + $this->y2plots[$i]->DoLegend($this); + } + } + + // Any plots on the extra Y axises? + $n = count($this->ynaxis); + for($i=0; $i<$n ; ++$i ) { + if( $this->ynplots == null || $this->ynplots[$i] == null) { + JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i"); + } + $m = count($this->ynplots[$i]); + for($j=0; $j < $m; ++$j ) { + $this->ynplots[$i][$j]->PreStrokeAdjust($this); + $this->ynplots[$i][$j]->DoLegend($this); + } + } + } + + function StrokeBands($aDepth,$aCSIM) { + // Stroke bands + if( $this->bands != null && !$aCSIM) { + for($i=0; $i < count($this->bands); ++$i) { + // Stroke all bands that asks to be in the background + if( $this->bands[$i]->depth == $aDepth ) { + $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); + } + } + } + + if( $this->y2bands != null && $this->y2scale != null && !$aCSIM ) { + for($i=0; $i < count($this->y2bands); ++$i) { + // Stroke all bands that asks to be in the foreground + if( $this->y2bands[$i]->depth == $aDepth ) { + $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); + } + } + } + } + + + // Stroke the graph + // $aStrokeFileName If != "" the image will be written to this file and NOT + // streamed back to the browser + function Stroke($aStrokeFileName='') { + + // Fist make a sanity check that user has specified a scale + if( empty($this->yscale) ) { + JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); + } + + // Start by adjusting the margin so that potential titles will fit. + $this->AdjustMarginsForTitles(); + + // Give the plot a chance to do any scale adjuments the individual plots + // wants to do. Right now this is only used by the contour plot to set scale + // limits + for($i=0; $i < count($this->plots) ; ++$i ) { + $this->plots[$i]->PreScaleSetup($this); + } + + // Init scale constants that are used to calculate the transformation from + // world to pixel coordinates + $this->InitScaleConstants(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // If we are called the second time (perhaps the user has called GetHTMLImageMap() + // himself then the legends have alsready been populated once in order to get the + // CSIM coordinats. Since we do not want the legends to be populated a second time + // we clear the legends + $this->legend->Clear(); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + // Setup pre-stroked adjustments and Legends + $this->doPrestrokeAdjustments(); + + // Bail out if any of the Y-axis not been specified and + // has no plots. (This means it is impossible to do autoscaling and + // no other scale was given so we can't possible draw anything). If you use manual + // scaling you also have to supply the tick steps as well. + if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || + ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { + //$e = "n=".count($this->y2plots)."\n"; + // $e = "Can't draw unspecified Y-scale.
      \nYou have either:
      \n"; + // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots
      \n"; + // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; + JpGraphError::RaiseL(25026); + } + + // Bail out if no plots and no specified X-scale + if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) { + JpGraphError::RaiseL(25034);//("JpGraph: Can't draw unspecified X-scale.
      No plots.
      "); + } + + // Autoscale the normal Y-axis + $this->doAutoScaleYAxis(); + + // Autoscale all additiopnal y-axis + $this->doAutoScaleYnAxis(); + + // Autoscale the regular x-axis and position the y-axis properly + $this->doAutoScaleXAxis(); + + // If we have a negative values and x-axis position is at 0 + // we need to supress the first and possible the last tick since + // they will be drawn on top of the y-axis (and possible y2 axis) + // The test below might seem strange the reasone being that if + // the user hasn't specified a value for position this will not + // be set until we do the stroke for the axis so as of now it + // is undefined. + // For X-text scale we ignore all this since the tick are usually + // much further in and not close to the Y-axis. Hence the test + // for 'text' + if( ($this->yaxis->pos==$this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && + !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && + substr($this->axtype,0,4) != 'text' && $this->xaxis->pos != 'min' ) { + + //$this->yscale->ticks->SupressZeroLabel(false); + $this->xscale->ticks->SupressFirst(); + if( $this->y2axis != null ) { + $this->xscale->ticks->SupressLast(); + } + } + elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) { + $this->xscale->ticks->SupressLast(); + } + + if( !$_csim ) { + $this->StrokePlotArea(); + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + } + $this->StrokeAxis(false); + + // Stroke colored bands + $this->StrokeBands(DEPTH_BACK,$_csim); + + if( $this->grid_depth == DEPTH_BACK && !$_csim) { + $this->ygrid->Stroke(); + $this->xgrid->Stroke(); + } + + // Stroke Y2-axis + if( $this->y2axis != null && !$_csim) { + $this->y2axis->Stroke($this->xscale); + $this->y2grid->Stroke(); + } + + // Stroke yn-axis + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + $this->ynaxis[$i]->Stroke($this->xscale); + } + + $oldoff=$this->xscale->off; + if( substr($this->axtype,0,4) == 'text' ) { + if( $this->text_scale_abscenteroff > -1 ) { + // For a text scale the scale factor is the number of pixel per step. + // Hence we can use the scale factor as a substitute for number of pixels + // per major scale step and use that in order to adjust the offset so that + // an object of width "abscenteroff" becomes centered. + $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2); + } + else { + $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); + } + } + + if( $this->iDoClipping ) { + $oldimage = $this->img->CloneCanvasH(); + } + + if( ! $this->y2orderback ) { + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); + $this->plots[$i]->StrokeMargin($this->img); + } + } + + // Stroke all plots for Y2 axis + if( $this->y2scale != null ) { + for($i=0; $i< count($this->y2plots); ++$i ) { + $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); + } + } + + if( $this->y2orderback ) { + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); + $this->plots[$i]->StrokeMargin($this->img); + } + } + + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + $m = count($this->ynplots[$i]); + for( $j=0; $j < $m; ++$j ) { + $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]); + $this->ynplots[$i][$j]->StrokeMargin($this->img); + } + } + + if( $this->iIconDepth == DEPTH_FRONT) { + $this->StrokeIcons(); + } + + if( $this->iDoClipping ) { + // Clipping only supports graphs at 0 and 90 degrees + if( $this->img->a == 0 ) { + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->left_margin,$this->img->top_margin, + $this->img->left_margin,$this->img->top_margin, + $this->img->plotwidth+1,$this->img->plotheight); + } + elseif( $this->img->a == 90 ) { + $adj = ($this->img->height - $this->img->width)/2; + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + $this->img->plotheight+1,$this->img->plotwidth); + } + else { + JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); + } + $this->img->Destroy(); + $this->img->SetCanvasH($oldimage); + } + + $this->xscale->off=$oldoff; + + if( $this->grid_depth == DEPTH_FRONT && !$_csim ) { + $this->ygrid->Stroke(); + $this->xgrid->Stroke(); + } + + // Stroke colored bands + $this->StrokeBands(DEPTH_FRONT,$_csim); + + // Finally draw the axis again since some plots may have nagged + // the axis in the edges. + if( !$_csim ) { + $this->StrokeAxis(); + } + + if( $this->y2scale != null && !$_csim ) { + $this->y2axis->Stroke($this->xscale,false); + } + + if( !$_csim ) { + $this->StrokePlotBox(); + } + + // The titles and legends never gets rotated so make sure + // that the angle is 0 before stroking them + $aa = $this->img->SetAngle(0); + $this->StrokeTitles(); + $this->footer->Stroke($this->img); + $this->legend->Stroke($this->img); + $this->img->SetAngle($aa); + $this->StrokeTexts(); + $this->StrokeTables(); + + if( !$_csim ) { + + $this->img->SetAngle($aa); + + // Draw an outline around the image map + if(_JPG_DEBUG) { + $this->DisplayClientSideaImageMapAreas(); + } + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + } + } + } + + function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') { + $this->iAxisLblBgType = $aType; + $this->iXAxisLblBgFillColor = $aXFColor; + $this->iXAxisLblBgColor = $aXColor; + $this->iYAxisLblBgFillColor = $aYFColor; + $this->iYAxisLblBgColor = $aYColor; + } + + function StrokeAxisLabelBackground() { + // Types + // 0 = No background + // 1 = Only X-labels, length of axis + // 2 = Only Y-labels, length of axis + // 3 = As 1 but extends to width of graph + // 4 = As 2 but extends to height of graph + // 5 = Combination of 3 & 4 + // 6 = Combination of 1 & 2 + + $t = $this->iAxisLblBgType ; + if( $t < 1 ) return; + + // Stroke optional X-axis label background color + if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) { + $this->img->PushColor($this->iXAxisLblBgFillColor); + if( $t == 1 || $t == 6 ) { + $xl = $this->img->left_margin; + $yu = $this->img->height - $this->img->bottom_margin + 1; + $xr = $this->img->width - $this->img->right_margin ; + $yl = $this->img->height-1-$this->frame_weight; + } + else { // t==3 || t==5 + $xl = $this->frame_weight; + $yu = $this->img->height - $this->img->bottom_margin + 1; + $xr = $this->img->width - 1 - $this->frame_weight; + $yl = $this->img->height-1-$this->frame_weight; + } + + $this->img->FilledRectangle($xl,$yu,$xr,$yl); + $this->img->PopColor(); + + // Check if we should add the vertical lines at left and right edge + if( $this->iXAxisLblBgColor !== '' ) { + // Hardcode to one pixel wide + $this->img->SetLineWeight(1); + $this->img->PushColor($this->iXAxisLblBgColor); + if( $t == 1 || $t == 6 ) { + $this->img->Line($xl,$yu,$xl,$yl); + $this->img->Line($xr,$yu,$xr,$yl); + } + else { + $xl = $this->img->width - $this->img->right_margin ; + $this->img->Line($xl,$yu-1,$xr,$yu-1); + } + $this->img->PopColor(); + } + } + + if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) { + $this->img->PushColor($this->iYAxisLblBgFillColor); + if( $t == 2 || $t == 6 ) { + $xl = $this->frame_weight; + $yu = $this->frame_weight+$this->img->top_margin; + $xr = $this->img->left_margin - 1; + $yl = $this->img->height - $this->img->bottom_margin + 1; + } + else { + $xl = $this->frame_weight; + $yu = $this->frame_weight; + $xr = $this->img->left_margin - 1; + $yl = $this->img->height-1-$this->frame_weight; + } + + $this->img->FilledRectangle($xl,$yu,$xr,$yl); + $this->img->PopColor(); + + // Check if we should add the vertical lines at left and right edge + if( $this->iXAxisLblBgColor !== '' ) { + $this->img->PushColor($this->iXAxisLblBgColor); + if( $t == 2 || $t == 6 ) { + $this->img->Line($xl,$yu-1,$xr,$yu-1); + $this->img->Line($xl,$yl-1,$xr,$yl-1); + } + else { + $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin); + } + $this->img->PopColor(); + } + + } + } + + function StrokeAxis($aStrokeLabels=true) { + + if( $aStrokeLabels ) { + $this->StrokeAxisLabelBackground(); + } + + // Stroke axis + if( $this->iAxisStyle != AXSTYLE_SIMPLE ) { + switch( $this->iAxisStyle ) { + case AXSTYLE_BOXIN : + $toppos = SIDE_DOWN; + $bottompos = SIDE_UP; + $leftpos = SIDE_RIGHT; + $rightpos = SIDE_LEFT; + break; + case AXSTYLE_BOXOUT : + $toppos = SIDE_UP; + $bottompos = SIDE_DOWN; + $leftpos = SIDE_LEFT; + $rightpos = SIDE_RIGHT; + break; + case AXSTYLE_YBOXIN: + $toppos = FALSE; + $bottompos = SIDE_UP; + $leftpos = SIDE_RIGHT; + $rightpos = SIDE_LEFT; + break; + case AXSTYLE_YBOXOUT: + $toppos = FALSE; + $bottompos = SIDE_DOWN; + $leftpos = SIDE_LEFT; + $rightpos = SIDE_RIGHT; + break; + default: + JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle); + break; + } + + // By default we hide the first label so it doesn't cross the + // Y-axis in case the positon hasn't been set by the user. + // However, if we use a box we always want the first value + // displayed so we make sure it will be displayed. + $this->xscale->ticks->SupressFirst(false); + + // Now draw the bottom X-axis + $this->xaxis->SetPos('min'); + $this->xaxis->SetLabelSide(SIDE_DOWN); + $this->xaxis->scale->ticks->SetSide($bottompos); + $this->xaxis->Stroke($this->yscale,$aStrokeLabels); + + if( $toppos !== FALSE ) { + // We also want a top X-axis + $this->xaxis = $this->xaxis; + $this->xaxis->SetPos('max'); + $this->xaxis->SetLabelSide(SIDE_UP); + // No title for the top X-axis + if( $aStrokeLabels ) { + $this->xaxis->title->Set(''); + } + $this->xaxis->scale->ticks->SetSide($toppos); + $this->xaxis->Stroke($this->yscale,$aStrokeLabels); + } + + // Stroke the left Y-axis + $this->yaxis->SetPos('min'); + $this->yaxis->SetLabelSide(SIDE_LEFT); + $this->yaxis->scale->ticks->SetSide($leftpos); + $this->yaxis->Stroke($this->xscale,$aStrokeLabels); + + // Stroke the right Y-axis + $this->yaxis->SetPos('max'); + // No title for the right side + if( $aStrokeLabels ) { + $this->yaxis->title->Set(''); + } + $this->yaxis->SetLabelSide(SIDE_RIGHT); + $this->yaxis->scale->ticks->SetSide($rightpos); + $this->yaxis->Stroke($this->xscale,$aStrokeLabels); + } + else { + $this->xaxis->Stroke($this->yscale,$aStrokeLabels); + $this->yaxis->Stroke($this->xscale,$aStrokeLabels); + } + } + + + // Private helper function for backgound image + static function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') { + if( $aImgStr != '' ) { + return Image::CreateFromString($aImgStr); + } + + // Remove case sensitivity and setup appropriate function to create image + // Get file extension. This should be the LAST '.' separated part of the filename + $e = explode('.',$aFile); + $ext = strtolower($e[count($e)-1]); + if ($ext == "jpeg") { + $ext = "jpg"; + } + + if( trim($ext) == '' ) { + $ext = 'png'; // Assume PNG if no extension specified + } + + if( $aImgFormat == '' ) { + $imgtag = $ext; + } + else { + $imgtag = $aImgFormat; + } + + $supported = imagetypes(); + if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || + ( $ext == 'gif' && !($supported & IMG_GIF) ) || + ( $ext == 'png' && !($supported & IMG_PNG) ) || + ( $ext == 'bmp' && !($supported & IMG_WBMP) ) || + ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) { + + JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); + } + + + if( $imgtag == "jpg" || $imgtag == "jpeg") { + $f = "imagecreatefromjpeg"; + $imgtag = "jpg"; + } + else { + $f = "imagecreatefrom".$imgtag; + } + + // Compare specified image type and file extension + if( $imgtag != $ext ) { + //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'"; + JpGraphError::RaiseL(25038, $aImgFormat, $aFile); + } + + $img = @$f($aFile); + if( !$img ) { + JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'"); + } + return $img; + } + + function StrokePlotGrad() { + if( $this->plot_gradtype < 0 ) + return; + + $grad = new Gradient($this->img); + $xl = $this->img->left_margin; + $yt = $this->img->top_margin; + $xr = $xl + $this->img->plotwidth+1 ; + $yb = $yt + $this->img->plotheight ; + $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->plot_gradfrom,$this->plot_gradto,$this->plot_gradtype); + + } + + function StrokeBackgroundGrad() { + if( $this->bkg_gradtype < 0 ) + return; + + $grad = new Gradient($this->img); + if( $this->bkg_gradstyle == BGRAD_PLOT ) { + $xl = $this->img->left_margin; + $yt = $this->img->top_margin; + $xr = $xl + $this->img->plotwidth+1 ; + $yb = $yt + $this->img->plotheight ; + $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); + } + else { + $xl = 0; + $yt = 0; + $xr = $xl + $this->img->width - 1; + $yb = $yt + $this->img->height - 1 ; + if( $this->doshadow ) { + $xr -= $this->shadow_width; + $yb -= $this->shadow_width; + } + if( $this->doframe ) { + $yt += $this->frame_weight; + $yb -= $this->frame_weight; + $xl += $this->frame_weight; + $xr -= $this->frame_weight; + } + $aa = $this->img->SetAngle(0); + $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); + $aa = $this->img->SetAngle($aa); + } + } + + function StrokeFrameBackground() { + if( $this->background_image != '' && $this->background_cflag != '' ) { + JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.'); + } + if( $this->background_image != '' ) { + $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image); + } + elseif( $this->background_cflag != '' ) { + if( ! class_exists('FlagImages',false) ) { + JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.'); + } + $fobj = new FlagImages(FLAGSIZE4); + $dummy=''; + $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy); + $this->background_image_mix = $this->background_cflag_mix; + $this->background_image_type = $this->background_cflag_type; + } + else { + return ; + } + + $bw = ImageSX($bkgimg); + $bh = ImageSY($bkgimg); + + // No matter what the angle is we always stroke the image and frame + // assuming it is 0 degree + $aa = $this->img->SetAngle(0); + + switch( $this->background_image_type ) { + case BGIMG_FILLPLOT: // Resize to just fill the plotarea + $this->FillMarginArea(); + $this->StrokeFrame(); + // Special case to hande 90 degree rotated graph corectly + if( $aa == 90 ) { + $this->img->SetAngle(90); + $this->FillPlotArea(); + $aa = $this->img->SetAngle(0); + $adj = ($this->img->height - $this->img->width)/2; + $this->img->CopyMerge($bkgimg, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + 0,0, + $this->img->plotheight+1,$this->img->plotwidth, + $bw,$bh,$this->background_image_mix); + } + else { + $this->FillPlotArea(); + $this->img->CopyMerge($bkgimg, + $this->img->left_margin,$this->img->top_margin+1, + 0,0,$this->img->plotwidth+1,$this->img->plotheight, + $bw,$bh,$this->background_image_mix); + } + break; + case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit + $hadj=0; $vadj=0; + if( $this->doshadow ) { + $hadj = $this->shadow_width; + $vadj = $this->shadow_width; + } + $this->FillMarginArea(); + $this->FillPlotArea(); + $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj, + $bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); + break; + case BGIMG_COPY: // Just copy the image from left corner, no resizing + $this->FillMarginArea(); + $this->FillPlotArea(); + $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh, + $bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); + break; + case BGIMG_CENTER: // Center original image in the plot area + $this->FillMarginArea(); + $this->FillPlotArea(); + $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); + $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); + $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh, + $bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); + break; + case BGIMG_FREE: // Just copy the image to the specified location + $this->img->CopyMerge($bkgimg, + $this->background_image_xpos,$this->background_image_ypos, + 0,0,$bw,$bh,$bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); // New + break; + default: + JpGraphError::RaiseL(25042);//(" Unknown background image layout"); + } + $this->img->SetAngle($aa); + } + + // Private + // Draw a frame around the image + function StrokeFrame() { + if( !$this->doframe ) return; + + if( $this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { + $c = $this->margin_color; + } + else { + $c = false; + } + + if( $this->doshadow ) { + $this->img->SetColor($this->frame_color); + $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, + $c,$this->shadow_width,$this->shadow_color); + } + elseif( $this->framebevel ) { + if( $c ) { + $this->img->SetColor($this->margin_color); + $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); + } + $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, + $this->framebeveldepth, + $this->framebevelcolor1,$this->framebevelcolor2); + if( $this->framebevelborder ) { + $this->img->SetColor($this->framebevelbordercolor); + $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); + } + } + else { + $this->img->SetLineWeight($this->frame_weight); + if( $c ) { + $this->img->SetColor($this->margin_color); + $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); + } + $this->img->SetColor($this->frame_color); + $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); + } + } + + function FillMarginArea() { + $hadj=0; $vadj=0; + if( $this->doshadow ) { + $hadj = $this->shadow_width; + $vadj = $this->shadow_width; + } + + $this->img->SetColor($this->margin_color); + // $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); + + $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); + $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); + $this->img->FilledRectangle($this->img->left_margin+1, + $this->img->height-$this->img->bottom_margin, + $this->img->width-1-$hadj, + $this->img->height-1-$hadj); + $this->img->FilledRectangle($this->img->width-$this->img->right_margin, + $this->img->top_margin+1, + $this->img->width-1-$hadj, + $this->img->height-$this->img->bottom_margin-1); + } + + function FillPlotArea() { + $this->img->PushColor($this->plotarea_color); + $this->img->FilledRectangle($this->img->left_margin, + $this->img->top_margin, + $this->img->width-$this->img->right_margin, + $this->img->height-$this->img->bottom_margin); + $this->img->PopColor(); + } + + // Stroke the plot area with either a solid color or a background image + function StrokePlotArea() { + // Note: To be consistent we really should take a possible shadow + // into account. However, that causes some problem for the LinearScale class + // since in the current design it does not have any links to class Graph which + // means it has no way of compensating for the adjusted plotarea in case of a + // shadow. So, until I redesign LinearScale we can't compensate for this. + // So just set the two adjustment parameters to zero for now. + $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ; + $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ; + + if( $this->background_image != '' || $this->background_cflag != '' ) { + $this->StrokeFrameBackground(); + } + else { + $aa = $this->img->SetAngle(0); + $this->StrokeFrame(); + $aa = $this->img->SetAngle($aa); + $this->StrokeBackgroundGrad(); + if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { + $this->FillPlotArea(); + } + $this->StrokePlotGrad(); + } + } + + function StrokeIcons() { + $n = count($this->iIcons); + for( $i=0; $i < $n; ++$i ) { + $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); + } + } + + function StrokePlotBox() { + // Should we draw a box around the plot area? + if( $this->boxed ) { + $this->img->SetLineWeight(1); + $this->img->SetLineStyle('solid'); + $this->img->SetColor($this->box_color); + for($i=0; $i < $this->box_weight; ++$i ) { + $this->img->Rectangle( + $this->img->left_margin-$i,$this->img->top_margin-$i, + $this->img->width-$this->img->right_margin+$i, + $this->img->height-$this->img->bottom_margin+$i); + } + } + } + + function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') { + $this->titlebkg_fillstyle = $aStyle; + $this->titlebkg_scolor1 = $aColor1; + $this->titlebkg_scolor2 = $aColor2; + } + + function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) { + $this->titlebackground = $aEnable; + $this->titlebackground_color = $aBackColor; + $this->titlebackground_style = $aStyle; + $this->titlebackground_framecolor = $aFrameColor; + $this->titlebackground_framestyle = $aFrameStyle; + $this->titlebackground_frameweight = $aFrameWeight; + $this->titlebackground_bevelheight = $aBevelHeight ; + } + + + function StrokeTitles() { + + $margin=3; + + if( $this->titlebackground ) { + // Find out height + $this->title->margin += 2 ; + $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin; + if( $this->subtitle->t != '' && !$this->subtitle->hide ) { + $h += $this->subtitle->GetTextHeight($this->img)+$margin+ + $this->subtitle->margin; + $h += 2; + } + if( $this->subsubtitle->t != '' && !$this->subsubtitle->hide ) { + $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+ + $this->subsubtitle->margin; + $h += 2; + } + $this->img->PushColor($this->titlebackground_color); + if( $this->titlebackground_style === TITLEBKG_STYLE1 ) { + // Inside the frame + if( $this->framebevel ) { + $x1 = $y1 = $this->framebeveldepth + 1 ; + $x2 = $this->img->width - $this->framebeveldepth - 2 ; + $this->title->margin += $this->framebeveldepth + 1 ; + $h += $y1 ; + $h += 2; + } + else { + $x1 = $y1 = $this->frame_weight; + $x2 = $this->img->width - $this->frame_weight-1; + } + } + elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) { + // Cover the frame as well + $x1 = $y1 = 0; + $x2 = $this->img->width - 1 ; + } + elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) { + // Cover the frame as well (the difference is that + // for style==3 a bevel frame border is on top + // of the title background) + $x1 = $y1 = 0; + $x2 = $this->img->width - 1 ; + $h += $this->framebeveldepth ; + $this->title->margin += $this->framebeveldepth ; + } + else { + JpGraphError::RaiseL(25043);//('Unknown title background style.'); + } + + if( $this->titlebackground_framestyle === 3 ) { + $h += $this->titlebackground_bevelheight*2 + 1 ; + $this->title->margin += $this->titlebackground_bevelheight ; + } + + if( $this->doshadow ) { + $x2 -= $this->shadow_width ; + } + + $indent=0; + if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { + $indent = $this->titlebackground_bevelheight; + } + + if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) { + $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent, + $this->titlebkg_scolor1, + $this->titlebkg_scolor2); + } + elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) { + $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent, + $this->titlebkg_scolor1, + $this->titlebkg_scolor2,2); + } + else { + // Solid fill + $this->img->FilledRectangle($x1,$y1,$x2,$h); + } + $this->img->PopColor(); + + $this->img->PushColor($this->titlebackground_framecolor); + $this->img->SetLineWeight($this->titlebackground_frameweight); + if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) { + // Frame background + $this->img->Rectangle($x1,$y1,$x2,$h); + } + elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) { + // Bottom line only + $this->img->Line($x1,$h,$x2,$h); + } + elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { + $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight); + } + $this->img->PopColor(); + + // This is clumsy. But we neeed to stroke the whole graph frame if it is + // set to bevel to get the bevel shading on top of the text background + if( $this->framebevel && $this->doframe && $this->titlebackground_style === 3 ) { + $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, + $this->framebeveldepth, + $this->framebevelcolor1,$this->framebevelcolor2); + if( $this->framebevelborder ) { + $this->img->SetColor($this->framebevelbordercolor); + $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); + } + } + } + + // Stroke title + $y = $this->title->margin; + if( $this->title->halign == 'center' ) { + $this->title->Center(0,$this->img->width,$y); + } + elseif( $this->title->halign == 'left' ) { + $this->title->SetPos($this->title->margin+2,$y); + } + elseif( $this->title->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right'); + } + $this->title->Stroke($this->img); + + // ... and subtitle + $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin; + if( $this->subtitle->halign == 'center' ) { + $this->subtitle->Center(0,$this->img->width,$y); + } + elseif( $this->subtitle->halign == 'left' ) { + $this->subtitle->SetPos($this->subtitle->margin+2,$y); + } + elseif( $this->subtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) + $indent = $this->shadow_width+2; + $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); + } + $this->subtitle->Stroke($this->img); + + // ... and subsubtitle + $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin; + if( $this->subsubtitle->halign == 'center' ) { + $this->subsubtitle->Center(0,$this->img->width,$y); + } + elseif( $this->subsubtitle->halign == 'left' ) { + $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); + } + elseif( $this->subsubtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) + $indent = $this->shadow_width+2; + $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); + } + $this->subsubtitle->Stroke($this->img); + + // ... and fancy title + $this->tabtitle->Stroke($this->img); + + } + + function StrokeTexts() { + // Stroke any user added text objects + if( $this->texts != null ) { + for($i=0; $i < count($this->texts); ++$i) { + $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); + } + } + + if( $this->y2texts != null && $this->y2scale != null ) { + for($i=0; $i < count($this->y2texts); ++$i) { + $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale); + } + } + + } + + function StrokeTables() { + if( $this->iTables != null ) { + $n = count($this->iTables); + for( $i=0; $i < $n; ++$i ) { + $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); + } + } + } + + function DisplayClientSideaImageMapAreas() { + // Debug stuff - display the outline of the image map areas + $csim=''; + foreach ($this->plots as $p) { + $csim.= $p->GetCSIMareas(); + } + $csim .= $this->legend->GetCSIMareas(); + if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { + $this->img->SetColor($this->csimcolor); + $n = count($coords[0]); + for ($i=0; $i < $n; $i++) { + if ( $coords[1][$i] == 'poly' ) { + preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); + $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); + $m = count($pts[0]); + for ($j=0; $j < $m; $j++) { + $this->img->LineTo($pts[1][$j],$pts[2][$j]); + } + } elseif ( $coords[1][$i] == 'rect' ) { + $pts = preg_split('/,/', $coords[2][$i]); + $this->img->SetStartPoint($pts[0],$pts[1]); + $this->img->LineTo($pts[2],$pts[1]); + $this->img->LineTo($pts[2],$pts[3]); + $this->img->LineTo($pts[0],$pts[3]); + $this->img->LineTo($pts[0],$pts[1]); + } + } + } + } + + // Text scale offset in world coordinates + function SetTextScaleOff($aOff) { + $this->text_scale_off = $aOff; + $this->xscale->text_scale_off = $aOff; + } + + // Text width of bar to be centered in absolute pixels + function SetTextScaleAbsCenterOff($aOff) { + $this->text_scale_abscenteroff = $aOff; + } + + // Get Y min and max values for added lines + function GetLinesYMinMax( $aLines ) { + $n = count($aLines); + if( $n == 0 ) return false; + $min = $aLines[0]->scaleposition ; + $max = $min ; + $flg = false; + for( $i=0; $i < $n; ++$i ) { + if( $aLines[$i]->direction == HORIZONTAL ) { + $flg = true ; + $v = $aLines[$i]->scaleposition ; + if( $min > $v ) $min = $v ; + if( $max < $v ) $max = $v ; + } + } + return $flg ? array($min,$max) : false ; + } + + // Get X min and max values for added lines + function GetLinesXMinMax( $aLines ) { + $n = count($aLines); + if( $n == 0 ) return false ; + $min = $aLines[0]->scaleposition ; + $max = $min ; + $flg = false; + for( $i=0; $i < $n; ++$i ) { + if( $aLines[$i]->direction == VERTICAL ) { + $flg = true ; + $v = $aLines[$i]->scaleposition ; + if( $min > $v ) $min = $v ; + if( $max < $v ) $max = $v ; + } + } + return $flg ? array($min,$max) : false ; + } + + // Get min and max values for all included plots + function GetPlotsYMinMax($aPlots) { + $n = count($aPlots); + $i=0; + do { + list($xmax,$max) = $aPlots[$i]->Max(); + } while( ++$i < $n && !is_numeric($max) ); + + $i=0; + do { + list($xmin,$min) = $aPlots[$i]->Min(); + } while( ++$i < $n && !is_numeric($min) ); + + if( !is_numeric($min) || !is_numeric($max) ) { + JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).'); + } + + for($i=0; $i < $n; ++$i ) { + list($xmax,$ymax)=$aPlots[$i]->Max(); + list($xmin,$ymin)=$aPlots[$i]->Min(); + if (is_numeric($ymax)) $max=max($max,$ymax); + if (is_numeric($ymin)) $min=min($min,$ymin); + } + if( $min == '' ) $min = 0; + if( $max == '' ) $max = 0; + if( $min == 0 && $max == 0 ) { + // Special case if all values are 0 + $min=0;$max=1; + } + return array($min,$max); + } + +} // Class + +//=================================================== +// CLASS LineProperty +// Description: Holds properties for a line +//=================================================== +class LineProperty { + public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=true; + + function __construct($aWeight=1,$aColor='black',$aStyle='solid') { + $this->iWeight = $aWeight; + $this->iColor = $aColor; + $this->iStyle = $aStyle; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetWeight($aWeight) { + $this->iWeight = $aWeight; + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function Show($aShow=true) { + $this->iShow=$aShow; + } + + function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) { + if( $this->iShow ) { + $aImg->PushColor($this->iColor); + $oldls = $aImg->line_style; + $oldlw = $aImg->line_weight; + $aImg->SetLineWeight($this->iWeight); + $aImg->SetLineStyle($this->iStyle); + $aImg->StyleLine($aX1,$aY1,$aX2,$aY2); + $aImg->PopColor($this->iColor); + $aImg->line_style = $oldls; + $aImg->line_weight = $oldlw; + + } + } +} + +//=================================================== +// CLASS GraphTabTitle +// Description: Draw "tab" titles on top of graphs +//=================================================== +class GraphTabTitle extends Text{ + private $corner = 6 , $posx = 7, $posy = 4; + private $fillcolor='lightyellow',$bordercolor='black'; + private $align = 'left', $width=TABTITLE_WIDTHFIT; + function __construct() { + $this->t = ''; + $this->font_style = FS_BOLD; + $this->hide = true; + $this->color = 'darkred'; + } + + function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') { + $this->color = $aTxtColor; + $this->fillcolor = $aFillColor; + $this->bordercolor = $aBorderColor; + } + + function SetFillColor($aFillColor) { + $this->fillcolor = $aFillColor; + } + + function SetTabAlign($aAlign) { + $this->align = $aAlign; + } + + function SetWidth($aWidth) { + $this->width = $aWidth ; + } + + function Set($t) { + $this->t = $t; + $this->hide = false; + } + + function SetCorner($aD) { + $this->corner = $aD ; + } + + function Stroke($aImg,$aDummy1=null,$aDummy2=null) { + if( $this->hide ) + return; + $this->boxed = false; + $w = $this->GetWidth($aImg) + 2*$this->posx; + $h = $this->GetTextHeight($aImg) + 2*$this->posy; + + $x = $aImg->left_margin; + $y = $aImg->top_margin; + + if( $this->width === TABTITLE_WIDTHFIT ) { + if( $this->align == 'left' ) { + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner,$y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + } + elseif( $this->align == 'center' ) { + $x += round($aImg->plotwidth/2) - round($w/2); + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner, $y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + } + else { + $x += $aImg->plotwidth -$w; + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner,$y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + } + } + else { + if( $this->width === TABTITLE_WIDTHFULL ) { + $w = $aImg->plotwidth ; + } + else { + $w = $this->width ; + } + + // Make the tab fit the width of the plot area + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner,$y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + + } + if( $this->halign == 'left' ) { + $aImg->SetTextAlign('left','bottom'); + $x += $this->posx; + $y -= $this->posy; + } + elseif( $this->halign == 'center' ) { + $aImg->SetTextAlign('center','bottom'); + $x += $w/2; + $y -= $this->posy; + } + else { + $aImg->SetTextAlign('right','bottom'); + $x += $w - $this->posx; + $y -= $this->posy; + } + + $aImg->SetColor($this->fillcolor); + $aImg->FilledPolygon($p); + + $aImg->SetColor($this->bordercolor); + $aImg->Polygon($p,true); + + $aImg->SetColor($this->color); + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->StrokeText($x,$y,$this->t,0,'center'); + } + +} + +//=================================================== +// CLASS SuperScriptText +// Description: Format a superscript text +//=================================================== +class SuperScriptText extends Text { + private $iSuper=''; + private $sfont_family='',$sfont_style='',$sfont_size=8; + private $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65; + private $iSDir=0; + private $iSimple=false; + + function __construct($aTxt='',$aSuper='',$aXAbsPos=0,$aYAbsPos=0) { + parent::__construct($aTxt,$aXAbsPos,$aYAbsPos); + $this->iSuper = $aSuper; + } + + function FromReal($aVal,$aPrecision=2) { + // Convert a floating point number to scientific notation + $neg=1.0; + if( $aVal < 0 ) { + $neg = -1.0; + $aVal = -$aVal; + } + + $l = floor(log10($aVal)); + $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision)); + $a *= $neg; + if( $this->iSimple && ($a == 1 || $a==-1) ) $a = ''; + + if( $a != '' ) { + $this->t = $a.' * 10'; + } + else { + if( $neg == 1 ) { + $this->t = '10'; + } + else { + $this->t = '-10'; + } + } + $this->iSuper = $l; + } + + function Set($aTxt,$aSuper='') { + $this->t = $aTxt; + $this->iSuper = $aSuper; + } + + function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) { + $this->sfont_family = $aFontFam; + $this->sfont_style = $aFontStyle; + $this->sfont_size = $aFontSize; + } + + // Total width of text + function GetWidth($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $w = $aImg->GetTextWidth($this->t); + $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); + $w += $aImg->GetTextWidth($this->iSuper); + $w += $this->iSuperMargin; + return $w; + } + + // Hight of font (approximate the height of the text) + function GetFontHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetFontHeight(); + $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); + $h += $aImg->GetFontHeight(); + return $h; + } + + // Hight of text + function GetTextHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetTextHeight($this->t); + $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); + $h += $aImg->GetTextHeight($this->iSuper); + return $h; + } + + function Stroke($aImg,$ax=-1,$ay=-1) { + + // To position the super script correctly we need different + // cases to handle the alignmewnt specified since that will + // determine how we can interpret the x,y coordinates + + $w = parent::GetWidth($aImg); + $h = parent::GetTextHeight($aImg); + switch( $this->valign ) { + case 'top': + $sy = $this->y; + break; + case 'center': + $sy = $this->y - $h/2; + break; + case 'bottom': + $sy = $this->y - $h; + break; + default: + JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text'); + break; + } + + switch( $this->halign ) { + case 'left': + $sx = $this->x + $w; + break; + case 'center': + $sx = $this->x + $w/2; + break; + case 'right': + $sx = $this->x; + break; + default: + JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text'); + break; + } + + $sx += $this->iSuperMargin; + $sy += $this->iVertOverlap; + + // Should we automatically determine the font or + // has the user specified it explicetly? + if( $this->sfont_family == '' ) { + if( $this->font_family <= FF_FONT2 ) { + if( $this->font_family == FF_FONT0 ) { + $sff = FF_FONT0; + } + elseif( $this->font_family == FF_FONT1 ) { + if( $this->font_style == FS_NORMAL ) { + $sff = FF_FONT0; + } + else { + $sff = FF_FONT1; + } + } + else { + $sff = FF_FONT1; + } + $sfs = $this->font_style; + $sfz = $this->font_size; + } + else { + // TTF fonts + $sff = $this->font_family; + $sfs = $this->font_style; + $sfz = floor($this->font_size*$this->iSuperScale); + if( $sfz < 8 ) $sfz = 8; + } + $this->sfont_family = $sff; + $this->sfont_style = $sfs; + $this->sfont_size = $sfz; + } + else { + $sff = $this->sfont_family; + $sfs = $this->sfont_style; + $sfz = $this->sfont_size; + } + + parent::Stroke($aImg,$ax,$ay); + + // For the builtin fonts we need to reduce the margins + // since the bounding bx reported for the builtin fonts + // are much larger than for the TTF fonts. + if( $sff <= FF_FONT2 ) { + $sx -= 2; + $sy += 3; + } + + $aImg->SetTextAlign('left','bottom'); + $aImg->SetFont($sff,$sfs,$sfz); + $aImg->PushColor($this->color); + $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left'); + $aImg->PopColor(); + } +} + + +//=================================================== +// CLASS Grid +// Description: responsible for drawing grid lines in graph +//=================================================== +class Grid { + protected $img; + protected $scale; + protected $majorcolor='#DDDDDD',$minorcolor='#EEEEEE'; + protected $majortype='solid',$minortype='solid'; + protected $show=false, $showMinor=false,$majorweight=1,$minorweight=1; + protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF'); + + function __construct($aAxis) { + $this->scale = $aAxis->scale; + $this->img = $aAxis->img; + } + + function SetColor($aMajColor,$aMinColor=false) { + $this->majorcolor=$aMajColor; + if( $aMinColor === false ) { + $aMinColor = $aMajColor ; + } + $this->minorcolor = $aMinColor; + } + + function SetWeight($aMajorWeight,$aMinorWeight=1) { + $this->majorweight=$aMajorWeight; + $this->minorweight=$aMinorWeight; + } + + // Specify if grid should be dashed, dotted or solid + function SetLineStyle($aMajorType,$aMinorType='solid') { + $this->majortype = $aMajorType; + $this->minortype = $aMinorType; + } + + function SetStyle($aMajorType,$aMinorType='solid') { + $this->SetLineStyle($aMajorType,$aMinorType); + } + + // Decide if both major and minor grid should be displayed + function Show($aShowMajor=true,$aShowMinor=false) { + $this->show=$aShowMajor; + $this->showMinor=$aShowMinor; + } + + function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') { + $this->fill = $aFlg; + $this->fillcolor = array( $aColor1, $aColor2 ); + } + + // Display the grid + function Stroke() { + if( $this->showMinor && !$this->scale->textscale ) { + $this->DoStroke($this->scale->ticks->ticks_pos,$this->minortype,$this->minorcolor,$this->minorweight); + $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight); + } + else { + $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight); + } + } + + //-------------- + // Private methods + // Draw the grid + function DoStroke($aTicksPos,$aType,$aColor,$aWeight) { + if( !$this->show ) return; + $nbrgrids = count($aTicksPos); + + if( $this->scale->type == 'y' ) { + $xl=$this->img->left_margin; + $xr=$this->img->width-$this->img->right_margin; + + if( $this->fill ) { + // Draw filled areas + $y2 = $aTicksPos[0]; + $i=1; + while( $i < $nbrgrids ) { + $y1 = $y2; + $y2 = $aTicksPos[$i++]; + $this->img->SetColor($this->fillcolor[$i & 1]); + $this->img->FilledRectangle($xl,$y1,$xr,$y2); + } + } + + $this->img->SetColor($aColor); + $this->img->SetLineWeight($aWeight); + + // Draw grid lines + switch( $aType ) { + case 'solid': $style = LINESTYLE_SOLID; break; + case 'dotted': $style = LINESTYLE_DOTTED; break; + case 'dashed': $style = LINESTYLE_DASHED; break; + case 'longdashed': $style = LINESTYLE_LONGDASH; break; + default: + $style = LINESTYLE_SOLID; break; + } + + for($i=0; $i < $nbrgrids; ++$i) { + $y=$aTicksPos[$i]; + $this->img->StyleLine($xl,$y,$xr,$y,$style); + } + } + elseif( $this->scale->type == 'x' ) { + $yu=$this->img->top_margin; + $yl=$this->img->height-$this->img->bottom_margin; + $limit=$this->img->width-$this->img->right_margin; + + if( $this->fill ) { + // Draw filled areas + $x2 = $aTicksPos[0]; + $i=1; + while( $i < $nbrgrids ) { + $x1 = $x2; + $x2 = min($aTicksPos[$i++],$limit) ; + $this->img->SetColor($this->fillcolor[$i & 1]); + $this->img->FilledRectangle($x1,$yu,$x2,$yl); + } + } + + $this->img->SetColor($aColor); + $this->img->SetLineWeight($aWeight); + + // We must also test for limit since we might have + // an offset and the number of ticks is calculated with + // assumption offset==0 so we might end up drawing one + // to many gridlines + $i=0; + $x=$aTicksPos[$i]; + while( $iimg->Line($x,$yl,$x,$yu); + elseif( $aType == 'dotted' ) $this->img->DashedLine($x,$yl,$x,$yu,1,6); + elseif( $aType == 'dashed' ) $this->img->DashedLine($x,$yl,$x,$yu,2,4); + elseif( $aType == 'longdashed' ) $this->img->DashedLine($x,$yl,$x,$yu,8,6); + ++$i; + } + } + else { + JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']'); + } + return true; + } +} // Class + +//=================================================== +// CLASS Axis +// Description: Defines X and Y axis. Notes that at the +// moment the code is not really good since the axis on +// several occasion must know wheter it's an X or Y axis. +// This was a design decision to make the code easier to +// follow. +//=================================================== +class AxisPrototype { + public $scale=null; + public $img=null; + public $hide=false,$hide_labels=false; + public $title=null; + public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0; + public $tick_step=1; + public $pos = false; + public $ticks_label = array(); + + protected $weight=1; + protected $color=array(0,0,0),$label_color=array(0,0,0); + protected $ticks_label_colors=null; + protected $show_first_label=true,$show_last_label=true; + protected $label_step=1; // Used by a text axis to specify what multiple of major steps + // should be labeled. + protected $labelPos=0; // Which side of the axis should the labels be? + protected $title_adjust,$title_margin,$title_side=SIDE_LEFT; + protected $tick_label_margin=5; + protected $label_halign = '',$label_valign = '', $label_para_align='left'; + protected $hide_line=false; + protected $iDeltaAbsPos=0; + + function __construct($img,$aScale,$color = array(0,0,0)) { + $this->img = $img; + $this->scale = $aScale; + $this->color = $color; + $this->title=new Text(''); + + if( $aScale->type == 'y' ) { + $this->title_margin = 25; + $this->title_adjust = 'middle'; + $this->title->SetOrientation(90); + $this->tick_label_margin=7; + $this->labelPos=SIDE_LEFT; + } + else { + $this->title_margin = 5; + $this->title_adjust = 'high'; + $this->title->SetOrientation(0); + $this->tick_label_margin=5; + $this->labelPos=SIDE_DOWN; + $this->title_side=SIDE_DOWN; + } + } + + function SetLabelFormat($aFormStr) { + $this->scale->ticks->SetLabelFormat($aFormStr); + } + + function SetLabelFormatString($aFormStr,$aDate=false) { + $this->scale->ticks->SetLabelFormat($aFormStr,$aDate); + } + + function SetLabelFormatCallback($aFuncName) { + $this->scale->ticks->SetFormatCallback($aFuncName); + } + + function SetLabelAlign($aHAlign,$aVAlign='top',$aParagraphAlign='left') { + $this->label_halign = $aHAlign; + $this->label_valign = $aVAlign; + $this->label_para_align = $aParagraphAlign; + } + + // Don't display the first label + function HideFirstTickLabel($aShow=false) { + $this->show_first_label=$aShow; + } + + function HideLastTickLabel($aShow=false) { + $this->show_last_label=$aShow; + } + + // Manually specify the major and (optional) minor tick position and labels + function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { + $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels); + } + + // Manually specify major tick positions and optional labels + function SetMajTickPositions($aMajPos,$aLabels=NULL) { + $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels); + } + + // Hide minor or major tick marks + function HideTicks($aHideMinor=true,$aHideMajor=true) { + $this->scale->ticks->SupressMinorTickMarks($aHideMinor); + $this->scale->ticks->SupressTickMarks($aHideMajor); + } + + // Hide zero label + function HideZeroLabel($aFlag=true) { + $this->scale->ticks->SupressZeroLabel(); + } + + function HideFirstLastLabel() { + // The two first calls to ticks method will supress + // automatically generated scale values. However, that + // will not affect manually specified value, e.g text-scales. + // therefor we also make a kludge here to supress manually + // specified scale labels. + $this->scale->ticks->SupressLast(); + $this->scale->ticks->SupressFirst(); + $this->show_first_label = false; + $this->show_last_label = false; + } + + // Hide the axis + function Hide($aHide=true) { + $this->hide=$aHide; + } + + // Hide the actual axis-line, but still print the labels + function HideLine($aHide=true) { + $this->hide_line = $aHide; + } + + function HideLabels($aHide=true) { + $this->hide_labels = $aHide; + } + + // Weight of axis + function SetWeight($aWeight) { + $this->weight = $aWeight; + } + + // Axis color + function SetColor($aColor,$aLabelColor=false) { + $this->color = $aColor; + if( !$aLabelColor ) $this->label_color = $aColor; + else $this->label_color = $aLabelColor; + } + + // Title on axis + function SetTitle($aTitle,$aAdjustAlign='high') { + $this->title->Set($aTitle); + $this->title_adjust=$aAdjustAlign; + } + + // Specify distance from the axis + function SetTitleMargin($aMargin) { + $this->title_margin=$aMargin; + } + + // Which side of the axis should the axis title be? + function SetTitleSide($aSideOfAxis) { + $this->title_side = $aSideOfAxis; + } + + function SetTickSide($aDir) { + $this->scale->ticks->SetSide($aDir); + } + + function SetTickSize($aMajSize,$aMinSize=3) { + $this->scale->ticks->SetSize($aMajSize,$aMinSize=3); + } + + // Specify text labels for the ticks. One label for each data point + function SetTickLabels($aLabelArray,$aLabelColorArray=null) { + $this->ticks_label = $aLabelArray; + $this->ticks_label_colors = $aLabelColorArray; + } + + function SetLabelMargin($aMargin) { + $this->tick_label_margin=$aMargin; + } + + // Specify that every $step of the ticks should be displayed starting + // at $start + function SetTextTickInterval($aStep,$aStart=0) { + $this->scale->ticks->SetTextLabelStart($aStart); + $this->tick_step=$aStep; + } + + // Specify that every $step tick mark should have a label + // should be displayed starting + function SetTextLabelInterval($aStep) { + if( $aStep < 1 ) { + JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1."); + } + $this->label_step=$aStep; + } + + function SetLabelSide($aSidePos) { + $this->labelPos=$aSidePos; + } + + // Set the font + function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { + $this->font_family = $aFamily; + $this->font_style = $aStyle; + $this->font_size = $aSize; + } + + // Position for axis line on the "other" scale + function SetPos($aPosOnOtherScale) { + $this->pos=$aPosOnOtherScale; + } + + // Set the position of the axis to be X-pixels delta to the right + // of the max X-position (used to position the multiple Y-axis) + function SetPosAbsDelta($aDelta) { + $this->iDeltaAbsPos=$aDelta; + } + + // Specify the angle for the tick labels + function SetLabelAngle($aAngle) { + $this->label_angle = $aAngle; + } + +} // Class + + +//=================================================== +// CLASS Axis +// Description: Defines X and Y axis. Notes that at the +// moment the code is not really good since the axis on +// several occasion must know wheter it's an X or Y axis. +// This was a design decision to make the code easier to +// follow. +//=================================================== +class Axis extends AxisPrototype { + + function __construct($img,$aScale,$color='black') { + parent::__construct($img,$aScale,$color); + } + + // Stroke the axis. + function Stroke($aOtherAxisScale,$aStrokeLabels=true) { + if( $this->hide ) + return; + if( is_numeric($this->pos) ) { + $pos=$aOtherAxisScale->Translate($this->pos); + } + else { // Default to minimum of other scale if pos not set + if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos == 'min' ) { + $pos = $aOtherAxisScale->scale_abs[0]; + } + elseif($this->pos == "max") { + $pos = $aOtherAxisScale->scale_abs[1]; + } + else { // If negative set x-axis at 0 + $this->pos=0; + $pos=$aOtherAxisScale->Translate(0); + } + } + $pos += $this->iDeltaAbsPos; + $this->img->SetLineWeight($this->weight); + $this->img->SetColor($this->color); + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + if( $this->scale->type == "x" ) { + if( !$this->hide_line ) { + $this->img->FilledRectangle($this->img->left_margin,$pos,$this->img->width-$this->img->right_margin,$pos+$this->weight-1); + } + if( $this->title_side == SIDE_DOWN ) { + $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; + $yalign = 'top'; + } + else { + $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin; + $yalign = 'bottom'; + } + + if( $this->title_adjust=='high' ) { + $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign); + } + elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) { + $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign); + } + elseif($this->title_adjust=='low') { + $this->title->SetPos($this->img->left_margin,$y,'left',$yalign); + } + else { + JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); + } + } + elseif( $this->scale->type == "y" ) { + // Add line weight to the height of the axis since + // the x-axis could have a width>1 and we want the axis to fit nicely together. + if( !$this->hide_line ) { + $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin,$pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); + } + $x=$pos ; + if( $this->title_side == SIDE_LEFT ) { + $x -= $this->title_margin; + $x -= $this->title->margin; + $halign = 'right'; + } + else { + $x += $this->title_margin; + $x += $this->title->margin; + $halign = 'left'; + } + // If the user has manually specified an hor. align + // then we override the automatic settings with this + // specifed setting. Since default is 'left' we compare + // with that. (This means a manually set 'left' align + // will have no effect.) + if( $this->title->halign != 'left' ) { + $halign = $this->title->halign; + } + if( $this->title_adjust == 'high' ) { + $this->title->SetPos($x,$this->img->top_margin,$halign,'top'); + } + elseif($this->title_adjust=='middle' || $this->title_adjust=='center') { + $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); + } + elseif($this->title_adjust=='low') { + $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,'bottom'); + } + else { + JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')'); + } + } + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + if( $aStrokeLabels ) { + if( !$this->hide_labels ) { + $this->StrokeLabels($pos); + } + $this->title->Stroke($this->img); + } + } + + //--------------- + // PRIVATE METHODS + // Draw all the tick labels on major tick marks + function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) { + + if( is_array($this->label_color) && count($this->label_color) > 3 ) { + $this->ticks_label_colors = $this->label_color; + $this->img->SetColor($this->label_color[0]); + } + else { + $this->img->SetColor($this->label_color); + } + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + $yoff=$this->img->GetFontHeight()/2; + + // Only draw labels at major tick marks + $nbr = count($this->scale->ticks->maj_ticks_label); + + // We have the option to not-display the very first mark + // (Usefull when the first label might interfere with another + // axis.) + $i = $this->show_first_label ? 0 : 1 ; + if( !$this->show_last_label ) { + --$nbr; + } + // Now run through all labels making sure we don't overshoot the end + // of the scale. + $ncolor=0; + if( isset($this->ticks_label_colors) ) { + $ncolor=count($this->ticks_label_colors); + } + while( $i < $nbr ) { + // $tpos holds the absolute text position for the label + $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; + + // Note. the $limit is only used for the x axis since we + // might otherwise overshoot if the scale has been centered + // This is due to us "loosing" the last tick mark if we center. + if( $this->scale->type == 'x' && $tpos > $this->img->width-$this->img->right_margin+1 ) { + return; + } + // we only draw every $label_step label + if( ($i % $this->label_step)==0 ) { + + // Set specific label color if specified + if( $ncolor > 0 ) { + $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); + } + + // If the label has been specified use that and in other case + // just label the mark with the actual scale value + $m=$this->scale->ticks->GetMajor(); + + // ticks_label has an entry for each data point and is the array + // that holds the labels set by the user. If the user hasn't + // specified any values we use whats in the automatically asigned + // labels in the maj_ticks_label + if( isset($this->ticks_label[$i*$m]) ) { + $label=$this->ticks_label[$i*$m]; + } + else { + if( $aAbsLabel ) { + $label=abs($this->scale->ticks->maj_ticks_label[$i]); + } + else { + $label=$this->scale->ticks->maj_ticks_label[$i]; + } + + // We number the scale from 1 and not from 0 so increase by one + if( $this->scale->textscale && + $this->scale->ticks->label_formfunc == '' && + ! $this->scale->ticks->HaveManualLabels() ) { + + ++$label; + + } + } + + if( $this->scale->type == "x" ) { + if( $this->labelPos == SIDE_DOWN ) { + if( $this->label_angle==0 || $this->label_angle==90 ) { + if( $this->label_halign=='' && $this->label_valign=='') { + $this->img->SetTextAlign('center','top'); + } + else { + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + + } + else { + if( $this->label_halign=='' && $this->label_valign=='') { + $this->img->SetTextAlign("right","top"); + } + else { + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + } + $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label, + $this->label_angle,$this->label_para_align); + } + else { + if( $this->label_angle==0 || $this->label_angle==90 ) { + if( $this->label_halign=='' && $this->label_valign=='') { + $this->img->SetTextAlign("center","bottom"); + } + else { + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + } + else { + if( $this->label_halign=='' && $this->label_valign=='') { + $this->img->SetTextAlign("right","bottom"); + } + else { + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + } + $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label, + $this->label_angle,$this->label_para_align); + } + } + else { + // scale->type == "y" + //if( $this->label_angle!=0 ) + //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis"); + if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis + if( $this->label_halign=='' && $this->label_valign=='') { + $this->img->SetTextAlign("right","center"); + } + else { + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); + } + else { // To the right of the y-axis + if( $this->label_halign=='' && $this->label_valign=='') { + $this->img->SetTextAlign("left","center"); + } + else { + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); + } + } + } + ++$i; + } + } + +} + + +//=================================================== +// CLASS Ticks +// Description: Abstract base class for drawing linear and logarithmic +// tick marks on axis +//=================================================== +class Ticks { + public $label_formatstr=''; // C-style format string to use for labels + public $label_formfunc=''; + public $label_dateformatstr=''; + public $direction=1; // Should ticks be in(=1) the plot area or outside (=-1) + public $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false; + public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), + $ticks_pos = array(), $maj_ticks_label = array(); + public $precision; + + protected $minor_abs_size=3, $major_abs_size=5; + protected $scale; + protected $is_set=false; + protected $supress_zerolabel=false,$supress_first=false; + protected $mincolor='',$majcolor=''; + protected $weight=1; + protected $label_usedateformat=FALSE; + + function __construct($aScale) { + $this->scale=$aScale; + $this->precision = -1; + } + + // Set format string for automatic labels + function SetLabelFormat($aFormatString,$aDate=FALSE) { + $this->label_formatstr=$aFormatString; + $this->label_usedateformat=$aDate; + } + + function SetLabelDateFormat($aFormatString) { + $this->label_dateformatstr=$aFormatString; + } + + function SetFormatCallback($aCallbackFuncName) { + $this->label_formfunc = $aCallbackFuncName; + } + + // Don't display the first zero label + function SupressZeroLabel($aFlag=true) { + $this->supress_zerolabel=$aFlag; + } + + // Don't display minor tick marks + function SupressMinorTickMarks($aHide=true) { + $this->supress_minor_tickmarks=$aHide; + } + + // Don't display major tick marks + function SupressTickMarks($aHide=true) { + $this->supress_tickmarks=$aHide; + } + + // Hide the first tick mark + function SupressFirst($aHide=true) { + $this->supress_first=$aHide; + } + + // Hide the last tick mark + function SupressLast($aHide=true) { + $this->supress_last=$aHide; + } + + // Size (in pixels) of minor tick marks + function GetMinTickAbsSize() { + return $this->minor_abs_size; + } + + // Size (in pixels) of major tick marks + function GetMajTickAbsSize() { + return $this->major_abs_size; + } + + function SetSize($aMajSize,$aMinSize=3) { + $this->major_abs_size = $aMajSize; + $this->minor_abs_size = $aMinSize; + } + + // Have the ticks been specified + function IsSpecified() { + return $this->is_set; + } + + function SetSide($aSide) { + $this->direction=$aSide; + } + + // Which side of the axis should the ticks be on + function SetDirection($aSide=SIDE_RIGHT) { + $this->direction=$aSide; + } + + // Set colors for major and minor tick marks + function SetMarkColor($aMajorColor,$aMinorColor='') { + $this->SetColor($aMajorColor,$aMinorColor); + } + + function SetColor($aMajorColor,$aMinorColor='') { + $this->majcolor=$aMajorColor; + + // If not specified use same as major + if( $aMinorColor == '' ) { + $this->mincolor=$aMajorColor; + } + else { + $this->mincolor=$aMinorColor; + } + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + +} // Class + +//=================================================== +// CLASS LinearTicks +// Description: Draw linear ticks on axis +//=================================================== +class LinearTicks extends Ticks { + public $minor_step=1, $major_step=2; + public $xlabel_offset=0,$xtick_offset=0; + private $label_offset=0; // What offset should the displayed label have + // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc + private $text_label_start=0; + private $iManualTickPos = NULL, $iManualMinTickPos = NULL, $iManualTickLabels = NULL; + private $iAdjustForDST = false; // If a date falls within the DST period add one hour to the diaplyed time + + function __construct() { + $this->precision = -1; + } + + // Return major step size in world coordinates + function GetMajor() { + return $this->major_step; + } + + // Return minor step size in world coordinates + function GetMinor() { + return $this->minor_step; + } + + // Set Minor and Major ticks (in world coordinates) + function Set($aMajStep,$aMinStep=false) { + if( $aMinStep==false ) { + $aMinStep=$aMajStep; + } + + if( $aMajStep <= 0 || $aMinStep <= 0 ) { + JpGraphError::RaiseL(25064); + //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); + } + + $this->major_step=$aMajStep; + $this->minor_step=$aMinStep; + $this->is_set = true; + } + + function SetMajTickPositions($aMajPos,$aLabels=NULL) { + $this->SetTickPositions($aMajPos,NULL,$aLabels); + } + + function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { + if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) { + JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()'); + return; + } + $n=count($aMajPos); + if( is_array($aLabels) && (count($aLabels) != $n) ) { + JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.'); + } + $this->iManualTickPos = $aMajPos; + $this->iManualMinTickPos = $aMinPos; + $this->iManualTickLabels = $aLabels; + } + + function HaveManualLabels() { + return count($this->iManualTickLabels) > 0; + } + + // Specify all the tick positions manually and possible also the exact labels + function _doManualTickPos($aScale) { + $n=count($this->iManualTickPos); + $m=count($this->iManualMinTickPos); + $doLbl=count($this->iManualTickLabels) > 0; + + $this->maj_ticks_pos = array(); + $this->maj_ticklabels_pos = array(); + $this->ticks_pos = array(); + + // Now loop through the supplied positions and translate them to screen coordinates + // and store them in the maj_label_positions + $minScale = $aScale->scale[0]; + $maxScale = $aScale->scale[1]; + $j=0; + for($i=0; $i < $n ; ++$i ) { + // First make sure that the first tick is not lower than the lower scale value + if( !isset($this->iManualTickPos[$i]) || $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) { + continue; + } + + $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]); + $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j]; + + // Set the minor tick marks the same as major if not specified + if( $m <= 0 ) { + $this->ticks_pos[$j] = $this->maj_ticks_pos[$j]; + } + if( $doLbl ) { + $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i]; + } + else { + $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n); + } + ++$j; + } + + // Some sanity check + if( count($this->maj_ticks_pos) < 2 ) { + JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.'); + } + + // Setup the minor tick marks + $j=0; + for($i=0; $i < $m; ++$i ) { + if( empty($this->iManualMinTickPos[$i]) || $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) { + continue; + } + $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]); + ++$j; + } + } + + function _doAutoTickPos($aScale) { + $maj_step_abs = $aScale->scale_factor*$this->major_step; + $min_step_abs = $aScale->scale_factor*$this->minor_step; + + if( $min_step_abs==0 || $maj_step_abs==0 ) { + JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')"); + } + // We need to make this an int since comparing it below + // with the result from round() can give wrong result, such that + // (40 < 40) == TRUE !!! + $limit = (int)$aScale->scale_abs[1]; + + if( $aScale->textscale ) { + // This can only be true for a X-scale (horizontal) + // Define ticks for a text scale. This is slightly different from a + // normal linear type of scale since the position might be adjusted + // and the labels start at on + $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset; + $start_abs=$aScale->scale_factor*$this->text_label_start; + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; + + $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs; + for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) { + // Apply format to label + $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks); + $label+=$this->major_step; + + // The x-position of the tick marks can be different from the labels. + // Note that we record the tick position (not the label) so that the grid + // happen upon tick marks and not labels. + $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs; + $this->maj_ticks_pos[$i]=$xtick; + $this->maj_ticklabels_pos[$i] = round($x); + $x += $maj_step_abs; + } + } + else { + $label = $aScale->GetMinVal(); + $abs_pos = $aScale->scale_abs[0]; + $j=0; $i=0; + $step = round($maj_step_abs/$min_step_abs); + if( $aScale->type == "x" ) { + // For a normal linear type of scale the major ticks will always be multiples + // of the minor ticks. In order to avoid any rounding issues the major ticks are + // defined as every "step" minor ticks and not calculated separately + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; + while( round($abs_pos) <= $limit ) { + $this->ticks_pos[] = round($abs_pos); + $this->ticks_label[] = $label; + if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) { + $this->maj_ticks_pos[$j] = round($abs_pos); + $this->maj_ticklabels_pos[$j] = round($abs_pos); + $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); + ++$j; + } + ++$i; + $abs_pos += $min_step_abs; + $label+=$this->minor_step; + } + } + elseif( $aScale->type == "y" ) { + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; + while( round($abs_pos) >= $limit ) { + $this->ticks_pos[$i] = round($abs_pos); + $this->ticks_label[$i]=$label; + if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) { + $this->maj_ticks_pos[$j] = round($abs_pos); + $this->maj_ticklabels_pos[$j] = round($abs_pos); + $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); + ++$j; + } + ++$i; + $abs_pos += $min_step_abs; + $label += $this->minor_step; + } + } + } + } + + function AdjustForDST($aFlg=true) { + $this->iAdjustForDST = $aFlg; + } + + + function _doLabelFormat($aVal,$aIdx,$aNbrTicks) { + + // If precision hasn't been specified set it to a sensible value + if( $this->precision==-1 ) { + $t = log10($this->minor_step); + if( $t > 0 ) { + $precision = 0; + } + else { + $precision = -floor($t); + } + } + else { + $precision = $this->precision; + } + + if( $this->label_formfunc != '' ) { + $f=$this->label_formfunc; + if( $this->label_formatstr == '' ) { + $l = call_user_func($f,$aVal); + } + else { + $l = sprintf($this->label_formatstr, call_user_func($f,$aVal)); + } + } + elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) { + if( $this->label_usedateformat ) { + // Adjust the value to take daylight savings into account + if (date("I",$aVal)==1 && $this->iAdjustForDST ) { + // DST + $aVal+=3600; + } + + $l = date($this->label_formatstr,$aVal); + if( $this->label_formatstr == 'W' ) { + // If we use week formatting then add a single 'w' in front of the + // week number to differentiate it from dates + $l = 'w'.$l; + } + } + else { + if( $this->label_dateformatstr !== '' ) { + // Adjust the value to take daylight savings into account + if (date("I",$aVal)==1 && $this->iAdjustForDST ) { + // DST + $aVal+=3600; + } + + $l = date($this->label_dateformatstr,$aVal); + if( $this->label_formatstr == 'W' ) { + // If we use week formatting then add a single 'w' in front of the + // week number to differentiate it from dates + $l = 'w'.$l; + } + } + else { + $l = sprintf($this->label_formatstr,$aVal); + } + } + } + else { + $l = sprintf('%01.'.$precision.'f',round($aVal,$precision)); + } + + if( ($this->supress_zerolabel && $l==0) || ($this->supress_first && $aIdx==0) || ($this->supress_last && $aIdx==$aNbrTicks-1) ) { + $l=''; + } + return $l; + } + + // Stroke ticks on either X or Y axis + function _StrokeTicks($aImg,$aScale,$aPos) { + $hor = $aScale->type == 'x'; + $aImg->SetLineWeight($this->weight); + + // We need to make this an int since comparing it below + // with the result from round() can give wrong result, such that + // (40 < 40) == TRUE !!! + $limit = (int)$aScale->scale_abs[1]; + + // A text scale doesn't have any minor ticks + if( !$aScale->textscale ) { + // Stroke minor ticks + $yu = $aPos - $this->direction*$this->GetMinTickAbsSize(); + $xr = $aPos + $this->direction*$this->GetMinTickAbsSize(); + $n = count($this->ticks_pos); + for($i=0; $i < $n; ++$i ) { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor != '') { + $aImg->PushColor($this->mincolor); + } + if( $hor ) { + //if( $this->ticks_pos[$i] <= $limit ) + $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); + } + else { + //if( $this->ticks_pos[$i] >= $limit ) + $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); + } + if( $this->mincolor != '' ) { + $aImg->PopColor(); + } + } + } + } + + // Stroke major ticks + $yu = $aPos - $this->direction*$this->GetMajTickAbsSize(); + $xr = $aPos + $this->direction*$this->GetMajTickAbsSize(); + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; + $n = count($this->maj_ticks_pos); + for($i=0; $i < $n ; ++$i ) { + if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { + if( $this->majcolor != '') { + $aImg->PushColor($this->majcolor); + } + if( $hor ) { + //if( $this->maj_ticks_pos[$i] <= $limit ) + $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); + } + else { + //if( $this->maj_ticks_pos[$i] >= $limit ) + $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); + } + if( $this->majcolor != '') { + $aImg->PopColor(); + } + } + } + + } + + // Draw linear ticks + function Stroke($aImg,$aScale,$aPos) { + if( $this->iManualTickPos != NULL ) { + $this->_doManualTickPos($aScale); + } + else { + $this->_doAutoTickPos($aScale); + } + $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' ); + } + + //--------------- + // PRIVATE METHODS + // Spoecify the offset of the displayed tick mark with the tick "space" + // Legal values for $o is [0,1] used to adjust where the tick marks and label + // should be positioned within the major tick-size + // $lo specifies the label offset and $to specifies the tick offset + // this comes in handy for example in bar graphs where we wont no offset for the + // tick but have the labels displayed halfway under the bars. + function SetXLabelOffset($aLabelOff,$aTickOff=-1) { + $this->xlabel_offset=$aLabelOff; + if( $aTickOff==-1 ) { + // Same as label offset + $this->xtick_offset=$aLabelOff; + } + else { + $this->xtick_offset=$aTickOff; + } + if( $aLabelOff>0 ) { + $this->SupressLast(); // The last tick wont fit + } + } + + // Which tick label should we start with? + function SetTextLabelStart($aTextLabelOff) { + $this->text_label_start=$aTextLabelOff; + } + +} // Class + +//=================================================== +// CLASS LinearScale +// Description: Handle linear scaling between screen and world +//=================================================== +class LinearScale { + public $textscale=false; // Just a flag to let the Plot class find out if + // we are a textscale or not. This is a cludge since + // this information is available in Graph::axtype but + // we don't have access to the graph object in the Plots + // stroke method. So we let graph store the status here + // when the linear scale is created. A real cludge... + public $type; // is this x or y scale ? + public $ticks=null; // Store ticks + public $text_scale_off = 0; + public $scale_abs=array(0,0); + public $scale_factor; // Scale factor between world and screen + public $off; // Offset between image edge and plot area + public $scale=array(0,0); + public $name = 'lin'; + public $auto_ticks=false; // When using manual scale should the ticks be automatically set? + public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php) + public $world_size; // Plot area size in world coordinates + public $intscale=false; // Restrict autoscale to integers + protected $autoscale_min=false; // Forced minimum value, auto determine max + protected $autoscale_max=false; // Forced maximum value, auto determine min + private $gracetop=0,$gracebottom=0; + + function __construct($aMin=0,$aMax=0,$aType='y') { + assert($aType=='x' || $aType=='y' ); + assert($aMin<=$aMax); + + $this->type=$aType; + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->ticks = new LinearTicks(); + } + + // Check if scale is set or if we should autoscale + // We should do this is either scale or ticks has not been set + function IsSpecified() { + if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set + return false; + } + return true; + } + + // Set the minimum data value when the autoscaling is used. + // Usefull if you want a fix minimum (like 0) but have an + // automatic maximum + function SetAutoMin($aMin) { + $this->autoscale_min=$aMin; + } + + // Set the minimum data value when the autoscaling is used. + // Usefull if you want a fix minimum (like 0) but have an + // automatic maximum + function SetAutoMax($aMax) { + $this->autoscale_max=$aMax; + } + + // If the user manually specifies a scale should the ticks + // still be set automatically? + function SetAutoTicks($aFlag=true) { + $this->auto_ticks = $aFlag; + } + + // Specify scale "grace" value (top and bottom) + function SetGrace($aGraceTop,$aGraceBottom=0) { + if( $aGraceTop<0 || $aGraceBottom < 0 ) { + JpGraphError::RaiseL(25069);//(" Grace must be larger then 0"); + } + $this->gracetop=$aGraceTop; + $this->gracebottom=$aGraceBottom; + } + + // Get the minimum value in the scale + function GetMinVal() { + return $this->scale[0]; + } + + // get maximum value for scale + function GetMaxVal() { + return $this->scale[1]; + } + + // Specify a new min/max value for sclae + function Update($aImg,$aMin,$aMax) { + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->InitConstants($aImg); + } + + // Translate between world and screen + function Translate($aCoord) { + if( !is_numeric($aCoord) ) { + if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) { + JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); + } + return 0; + } + else { + return round($this->off+($aCoord - $this->scale[0]) * $this->scale_factor); + } + } + + // Relative translate (don't include offset) usefull when we just want + // to know the relative position (in pixels) on the axis + function RelTranslate($aCoord) { + if( !is_numeric($aCoord) ) { + if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) { + JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); + } + return 0; + } + else { + return ($aCoord - $this->scale[0]) * $this->scale_factor; + } + } + + // Restrict autoscaling to only use integers + function SetIntScale($aIntScale=true) { + $this->intscale=$aIntScale; + } + + // Calculate an integer autoscale + function IntAutoScale($img,$min,$max,$maxsteps,$majend=true) { + // Make sure limits are integers + $min=floor($min); + $max=ceil($max); + if( abs($min-$max)==0 ) { + --$min; ++$max; + } + $maxsteps = floor($maxsteps); + + $gracetop=round(($this->gracetop/100.0)*abs($max-$min)); + $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min)); + if( is_numeric($this->autoscale_min) ) { + $min = ceil($this->autoscale_min); + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + } + + if( is_numeric($this->autoscale_max) ) { + $max = ceil($this->autoscale_max); + if( $min >= $max ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + } + + if( abs($min-$max ) == 0 ) { + ++$max; + --$min; + } + + $min -= $gracebottom; + $max += $gracetop; + + // First get tickmarks as multiples of 1, 10, ... + if( $majend ) { + list($num1steps,$adj1min,$adj1max,$maj1step) = $this->IntCalcTicks($maxsteps,$min,$max,1); + } + else { + $adj1min = $min; + $adj1max = $max; + list($num1steps,$maj1step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,1); + } + + if( abs($min-$max) > 2 ) { + // Then get tick marks as 2:s 2, 20, ... + if( $majend ) { + list($num2steps,$adj2min,$adj2max,$maj2step) = $this->IntCalcTicks($maxsteps,$min,$max,5); + } + else { + $adj2min = $min; + $adj2max = $max; + list($num2steps,$maj2step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,5); + } + } + else { + $num2steps = 10000; // Dummy high value so we don't choose this + } + + if( abs($min-$max) > 5 ) { + // Then get tickmarks as 5:s 5, 50, 500, ... + if( $majend ) { + list($num5steps,$adj5min,$adj5max,$maj5step) = $this->IntCalcTicks($maxsteps,$min,$max,2); + } + else { + $adj5min = $min; + $adj5max = $max; + list($num5steps,$maj5step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,2); + } + } + else { + $num5steps = 10000; // Dummy high value so we don't choose this + } + + // Check to see whichof 1:s, 2:s or 5:s fit better with + // the requested number of major ticks + $match1=abs($num1steps-$maxsteps); + $match2=abs($num2steps-$maxsteps); + if( !empty($maj5step) && $maj5step > 1 ) { + $match5=abs($num5steps-$maxsteps); + } + else { + $match5=10000; // Dummy high value + } + + // Compare these three values and see which is the closest match + // We use a 0.6 weight to gravitate towards multiple of 5:s + if( $match1 < $match2 ) { + if( $match1 < $match5 ) $r=1; + else $r=3; + } + else { + if( $match2 < $match5 ) $r=2; + else $r=3; + } + // Minsteps are always the same as maxsteps for integer scale + switch( $r ) { + case 1: + $this->ticks->Set($maj1step,$maj1step); + $this->Update($img,$adj1min,$adj1max); + break; + case 2: + $this->ticks->Set($maj2step,$maj2step); + $this->Update($img,$adj2min,$adj2max); + break; + case 3: + $this->ticks->Set($maj5step,$maj5step); + $this->Update($img,$adj5min,$adj5max); + break; + default: + JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)'); + } + } + + + // Calculate autoscale. Used if user hasn't given a scale and ticks + // $maxsteps is the maximum number of major tickmarks allowed. + function AutoScale($img,$min,$max,$maxsteps,$majend=true) { + + if( !is_numeric($min) || !is_numeric($max) ) { + JpGraphError::Raise(25044); + } + + if( $this->intscale ) { + $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); + return; + } + if( abs($min-$max) < 0.00001 ) { + // We need some difference to be able to autoscale + // make it 5% above and 5% below value + if( $min==0 && $max==0 ) { // Special case + $min=-1; $max=1; + } + else { + $delta = (abs($max)+abs($min))*0.005; + $min -= $delta; + $max += $delta; + } + } + + $gracetop=($this->gracetop/100.0)*abs($max-$min); + $gracebottom=($this->gracebottom/100.0)*abs($max-$min); + if( is_numeric($this->autoscale_min) ) { + $min = $this->autoscale_min; + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + if( abs($min-$max ) < 0.001 ) { + $max *= 1.2; + } + } + + if( is_numeric($this->autoscale_max) ) { + $max = $this->autoscale_max; + if( $min >= $max ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + if( abs($min-$max ) < 0.001 ) { + $min *= 0.8; + } + } + + $min -= $gracebottom; + $max += $gracetop; + + // First get tickmarks as multiples of 0.1, 1, 10, ... + if( $majend ) { + list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = $this->CalcTicks($maxsteps,$min,$max,1,2); + } + else { + $adj1min=$min; + $adj1max=$max; + list($num1steps,$min1step,$maj1step) = $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false); + } + + // Then get tick marks as 2:s 0.2, 2, 20, ... + if( $majend ) { + list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = $this->CalcTicks($maxsteps,$min,$max,5,2); + } + else { + $adj2min=$min; + $adj2max=$max; + list($num2steps,$min2step,$maj2step) = $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false); + } + + // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... + if( $majend ) { + list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = $this->CalcTicks($maxsteps,$min,$max,2,5); + } + else { + $adj5min=$min; + $adj5max=$max; + list($num5steps,$min5step,$maj5step) = $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false); + } + + // Check to see whichof 1:s, 2:s or 5:s fit better with + // the requested number of major ticks + $match1=abs($num1steps-$maxsteps); + $match2=abs($num2steps-$maxsteps); + $match5=abs($num5steps-$maxsteps); + + // Compare these three values and see which is the closest match + // We use a 0.8 weight to gravitate towards multiple of 5:s + $r=$this->MatchMin3($match1,$match2,$match5,0.8); + switch( $r ) { + case 1: + $this->Update($img,$adj1min,$adj1max); + $this->ticks->Set($maj1step,$min1step); + break; + case 2: + $this->Update($img,$adj2min,$adj2max); + $this->ticks->Set($maj2step,$min2step); + break; + case 3: + $this->Update($img,$adj5min,$adj5max); + $this->ticks->Set($maj5step,$min5step); + break; + } + } + + //--------------- + // PRIVATE METHODS + + // This method recalculates all constants that are depending on the + // margins in the image. If the margins in the image are changed + // this method should be called for every scale that is registred with + // that image. Should really be installed as an observer of that image. + function InitConstants($img) { + if( $this->type=='x' ) { + $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; + $this->off=$img->left_margin; + $this->scale_factor = 0; + if( $this->world_size > 0 ) { + $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); + } + } + else { // y scale + $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; + $this->off=$img->top_margin+$this->world_abs_size; + $this->scale_factor = 0; + if( $this->world_size > 0 ) { + $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0); + } + } + $size = $this->world_size * $this->scale_factor; + $this->scale_abs=array($this->off,$this->off + $size); + } + + // Initialize the conversion constants for this scale + // This tries to pre-calculate as much as possible to speed up the + // actual conversion (with Translate()) later on + // $start =scale start in absolute pixels (for x-scale this is an y-position + // and for an y-scale this is an x-position + // $len =absolute length in pixels of scale + function SetConstants($aStart,$aLen) { + $this->world_abs_size=$aLen; + $this->off=$aStart; + + if( $this->world_size<=0 ) { + // This should never ever happen !! + JpGraphError::RaiseL(25074); + //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale]
      Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); + } + + // scale_factor = number of pixels per world unit + $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); + + // scale_abs = start and end points of scale in absolute pixels + $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); + } + + + // Calculate number of ticks steps with a specific division + // $a is the divisor of 10**x to generate the first maj tick intervall + // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,... + // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,... + // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,... + // We return a vector of + // [$numsteps,$adjmin,$adjmax,$minstep,$majstep] + // If $majend==true then the first and last marks on the axis will be major + // labeled tick marks otherwise it will be adjusted to the closest min tick mark + function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) { + $diff=$max-$min; + if( $diff==0 ) { + $ld=0; + } + else { + $ld=floor(log10($diff)); + } + + // Gravitate min towards zero if we are close + if( $min>0 && $min < pow(10,$ld) ) $min=0; + + //$majstep=pow(10,$ld-1)/$a; + $majstep=pow(10,$ld)/$a; + $minstep=$majstep/$b; + + $adjmax=ceil($max/$minstep)*$minstep; + $adjmin=floor($min/$minstep)*$minstep; + $adjdiff = $adjmax-$adjmin; + $numsteps=$adjdiff/$majstep; + + while( $numsteps>$maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=$adjdiff/$majstep; + ++$ld; + } + + $minstep=$majstep/$b; + $adjmin=floor($min/$minstep)*$minstep; + $adjdiff = $adjmax-$adjmin; + if( $majend ) { + $adjmin = floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; + } + else { + $adjmax=ceil($max/$minstep)*$minstep; + } + + return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); + } + + function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) { + // Same as CalcTicks but don't adjust min/max values + $diff=$max-$min; + if( $diff==0 ) { + $ld=0; + } + else { + $ld=floor(log10($diff)); + } + + //$majstep=pow(10,$ld-1)/$a; + $majstep=pow(10,$ld)/$a; + $minstep=$majstep/$b; + $numsteps=floor($diff/$majstep); + + while( $numsteps > $maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=floor($diff/$majstep); + ++$ld; + } + $minstep=$majstep/$b; + return array($numsteps,$minstep,$majstep); + } + + + function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) { + $diff=$max-$min; + if( $diff==0 ) { + JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); + } + else { + $ld=floor(log10($diff)); + } + + // Gravitate min towards zero if we are close + if( $min>0 && $min < pow(10,$ld) ) { + $min=0; + } + if( $ld == 0 ) { + $ld=1; + } + if( $a == 1 ) { + $majstep = 1; + } + else { + $majstep=pow(10,$ld)/$a; + } + $adjmax=ceil($max/$majstep)*$majstep; + + $adjmin=floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + $numsteps=$adjdiff/$majstep; + while( $numsteps>$maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=$adjdiff/$majstep; + ++$ld; + } + + $adjmin=floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + if( $majend ) { + $adjmin = floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; + } + else { + $adjmax=ceil($max/$majstep)*$majstep; + } + + return array($numsteps,$adjmin,$adjmax,$majstep); + } + + + function IntCalcTicksFreeze($maxsteps,$min,$max,$a) { + // Same as IntCalcTick but don't change min/max values + $diff=$max-$min; + if( $diff==0 ) { + JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); + } + else { + $ld=floor(log10($diff)); + } + if( $ld == 0 ) { + $ld=1; + } + if( $a == 1 ) { + $majstep = 1; + } + else { + $majstep=pow(10,$ld)/$a; + } + + $numsteps=floor($diff/$majstep); + while( $numsteps > $maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=floor($diff/$majstep); + ++$ld; + } + + return array($numsteps,$majstep); + } + + // Determine the minimum of three values witha weight for last value + function MatchMin3($a,$b,$c,$weight) { + if( $a < $b ) { + if( $a < ($c*$weight) ) { + return 1; // $a smallest + } + else { + return 3; // $c smallest + } + } + elseif( $b < ($c*$weight) ) { + return 2; // $b smallest + } + return 3; // $c smallest + } +} // Class + + +//=================================================== +// CLASS DisplayValue +// Description: Used to print data values at data points +//=================================================== +class DisplayValue { + public $margin=5; + public $show=false; + public $valign='',$halign='center'; + public $format='%.1f',$negformat=''; + private $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10; + private $iFormCallback=''; + private $angle=0; + private $color='navy',$negcolor=''; + private $iHideZero=false; + public $txt=null; + + function __construct() { + $this->txt = new Text(); + } + + function Show($aFlag=true) { + $this->show=$aFlag; + } + + function SetColor($aColor,$aNegcolor='') { + $this->color = $aColor; + $this->negcolor = $aNegcolor; + } + + function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->ff=$aFontFamily; + $this->fs=$aFontStyle; + $this->fsize=$aFontSize; + } + + function ApplyFont($aImg) { + $aImg->SetFont($this->ff,$this->fs,$this->fsize); + } + + function SetMargin($aMargin) { + $this->margin = $aMargin; + } + + function SetAngle($aAngle) { + $this->angle = $aAngle; + } + + function SetAlign($aHAlign,$aVAlign='') { + $this->halign = $aHAlign; + $this->valign = $aVAlign; + } + + function SetFormat($aFormat,$aNegFormat='') { + $this->format= $aFormat; + $this->negformat= $aNegFormat; + } + + function SetFormatCallback($aFunc) { + $this->iFormCallback = $aFunc; + } + + function HideZero($aFlag=true) { + $this->iHideZero=$aFlag; + } + + function Stroke($img,$aVal,$x,$y) { + + if( $this->show ) + { + if( $this->negformat=='' ) { + $this->negformat=$this->format; + } + if( $this->negcolor=='' ) { + $this->negcolor=$this->color; + } + + if( $aVal===NULL || (is_string($aVal) && ($aVal=='' || $aVal=='-' || $aVal=='x' ) ) ) { + return; + } + + if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) { + return; + } + + // Since the value is used in different cirumstances we need to check what + // kind of formatting we shall use. For example, to display values in a line + // graph we simply display the formatted value, but in the case where the user + // has already specified a text string we don't fo anything. + if( $this->iFormCallback != '' ) { + $f = $this->iFormCallback; + $sval = call_user_func($f,$aVal); + } + elseif( is_numeric($aVal) ) { + if( $aVal >= 0 ) { + $sval=sprintf($this->format,$aVal); + } + else { + $sval=sprintf($this->negformat,$aVal); + } + } + else { + $sval=$aVal; + } + + $y = $y-sign($aVal)*$this->margin; + + $this->txt->Set($sval); + $this->txt->SetPos($x,$y); + $this->txt->SetFont($this->ff,$this->fs,$this->fsize); + if( $this->valign == '' ) { + if( $aVal >= 0 ) { + $valign = "bottom"; + } + else { + $valign = "top"; + } + } + else { + $valign = $this->valign; + } + $this->txt->Align($this->halign,$valign); + + $this->txt->SetOrientation($this->angle); + if( $aVal > 0 ) { + $this->txt->SetColor($this->color); + } + else { + $this->txt->SetColor($this->negcolor); + } + $this->txt->Stroke($img); + } + } +} + +//=================================================== +// CLASS Plot +// Description: Abstract base class for all concrete plot classes +//=================================================== +class Plot { + public $numpoints=0; + public $value; + public $legend=''; + public $coords=array(); + public $color='black'; + public $hidelegend=false; + public $line_weight=1; + public $csimtargets=array(),$csimwintargets=array(); // Array of targets for CSIM + public $csimareas=''; // Resultant CSIM area tags + public $csimalts=null; // ALT:s for corresponding target + public $legendcsimtarget='',$legendcsimwintarget=''; + public $legendcsimalt=''; + protected $weight=1; + protected $center=false; + + function __construct($aDatay,$aDatax=false) { + $this->numpoints = count($aDatay); + if( $this->numpoints==0 ) { + JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); + } + $this->coords[0]=$aDatay; + if( is_array($aDatax) ) { + $this->coords[1]=$aDatax; + $n = count($aDatax); + for( $i=0; $i < $n; ++$i ) { + if( !is_numeric($aDatax[$i]) ) { + JpGraphError::RaiseL(25070); + } + } + } + $this->value = new DisplayValue(); + } + + // Stroke the plot + // "virtual" function which must be implemented by + // the subclasses + function Stroke($aImg,$aXScale,$aYScale) { + JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot"); + } + + function HideLegend($f=true) { + $this->hidelegend = $f; + } + + function DoLegend($graph) { + if( !$this->hidelegend ) + $this->Legend($graph); + } + + function StrokeDataValue($img,$aVal,$x,$y) { + $this->value->Stroke($img,$aVal,$x,$y); + } + + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { + $this->csimtargets=$aTargets; + $this->csimwintargets=$aWinTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + // "Virtual" function which gets called before any scale + // or axis are stroked used to do any plot specific adjustment + function PreStrokeAdjust($aGraph) { + if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) { + JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); + } + return true; + } + + // Virtual function to the the concrete plot class to make any changes to the graph + // and scale before the stroke process begins + function PreScaleSetup($aGraph) { + // Empty + } + + // Get minimum values in plot + function Min() { + if( isset($this->coords[1]) ) { + $x=$this->coords[1]; + } + else { + $x=''; + } + if( $x != '' && count($x) > 0 ) { + $xm=min($x); + } + else { + $xm=0; + } + $y=$this->coords[0]; + $cnt = count($y); + if( $cnt > 0 ) { + $i=0; + while( $i<$cnt && !is_numeric($ym=$y[$i]) ) { + $i++; + } + while( $i < $cnt) { + if( is_numeric($y[$i]) ) { + $ym=min($ym,$y[$i]); + } + ++$i; + } + } + else { + $ym=''; + } + return array($xm,$ym); + } + + // Get maximum value in plot + function Max() { + if( isset($this->coords[1]) ) { + $x=$this->coords[1]; + } + else { + $x=''; + } + + if( $x!='' && count($x) > 0 ) { + $xm=max($x); + } + else { + $xm = $this->numpoints-1; + } + $y=$this->coords[0]; + if( count($y) > 0 ) { + $cnt = count($y); + $i=0; + while( $i<$cnt && !is_numeric($ym=$y[$i]) ) { + $i++; + } + while( $i < $cnt ) { + if( is_numeric($y[$i]) ) { + $ym=max($ym,$y[$i]); + } + ++$i; + } + } + else { + $ym=''; + } + return array($xm,$ym); + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimwintarget = $aCSIMWinTarget; + $this->legendcsimalt = $aCSIMAlt; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + function SetLineWeight($aWeight=1) { + $this->line_weight=$aWeight; + } + + function SetCenter($aCenter=true) { + $this->center = $aCenter; + } + + // This method gets called by Graph class to plot anything that should go + // into the margin after the margin color has been set. + function StrokeMargin($aImg) { + return true; + } + + // Framework function the chance for each plot class to set a legend + function Legend($aGraph) { + if( $this->legend != '' ) { + $aGraph->legend->Add($this->legend,$this->color,'',0,$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + +} // Class + + +// Provide a deterministic list of new colors whenever the getColor() method +// is called. Used to automatically set colors of plots. +class ColorFactory { + + static private $iIdx = 0; + static private $iColorList = array( + 'black', + 'blue', + 'orange', + 'darkgreen', + 'red', + 'AntiqueWhite3', + 'aquamarine3', + 'azure4', + 'brown', + 'cadetblue3', + 'chartreuse4', + 'chocolate', + 'darkblue', + 'darkgoldenrod3', + 'darkorchid3', + 'darksalmon', + 'darkseagreen4', + 'deepskyblue2', + 'dodgerblue4', + 'gold3', + 'hotpink', + 'lawngreen', + 'lightcoral', + 'lightpink3', + 'lightseagreen', + 'lightslateblue', + 'mediumpurple', + 'olivedrab', + 'orangered1', + 'peru', + 'slategray', + 'yellow4', + 'springgreen2'); + static private $iNum = 33; + + static function getColor() { + if( ColorFactory::$iIdx >= ColorFactory::$iNum ) + ColorFactory::$iIdx = 0; + return ColorFactory::$iColorList[ColorFactory::$iIdx++]; + } + +} + +// +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_antispam-digits.php b/ext/jpgraph-3.0.7/src/jpgraph_antispam-digits.php index d435384..73fa57a 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_antispam-digits.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_antispam-digits.php @@ -1,205 +1,205 @@ -digits['6'][0]= 645 ; - $this->digits['6'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. - 'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. - 'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. - 'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. - 'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. - 'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. - 'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; - - //========================================================== - // d2-small.jpg - //========================================================== - $this->digits['2'][0]= 606 ; - $this->digits['2'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. - 'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. - 'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. - 'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. - 'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. - '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. - 'DLZ6f//Z' ; - - //========================================================== - // d9-small.jpg - //========================================================== - $this->digits['9'][0]= 680 ; - $this->digits['9'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. - 'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. - 'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. - 'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. - 'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. - 'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. - 'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. - '1V1//9k=' ; - - //========================================================== - // d5-small.jpg - //========================================================== - $this->digits['5'][0]= 632 ; - $this->digits['5'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. - 'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. - 'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. - 'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. - 'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. - 'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. - '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; - - //========================================================== - // d1-small.jpg - //========================================================== - $this->digits['1'][0]= 646 ; - $this->digits['1'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. - 'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. - 'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. - 'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. - 'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. - 'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. - 'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; - - //========================================================== - // d8-small.jpg - //========================================================== - $this->digits['8'][0]= 694 ; - $this->digits['8'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. - 'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. - 'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. - 'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. - '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. - 'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. - 'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. - 'EylmLHQltptPZKQOBo1FzH//2Q==' ; - - //========================================================== - // d4-small.jpg - //========================================================== - $this->digits['4'][0]= 643 ; - $this->digits['4'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. - 'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. - 'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. - 'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. - 'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. - '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. - 'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; - - //========================================================== - // d7-small.jpg - //========================================================== - $this->digits['7'][0]= 658 ; - $this->digits['7'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. - 'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. - 'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. - '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. - 'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. - '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. - 'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; - - //========================================================== - // d3-small.jpg - //========================================================== - $this->digits['3'][0]= 662 ; - $this->digits['3'][1]= - '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. - 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. - 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. - 'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. - 'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. - 'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. - 'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. - 'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. - 'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; - } -} - -class AntiSpam { - - var $iNumber=''; - - function __construct($aNumber='') { - $this->iNumber = $aNumber; - } - - function Rand($aLen) { - $d=''; - for($i=0; $i < $aLen; ++$i) { - $d .= rand(1,9); - } - $this->iNumber = $d; - return $d; - } - - function Stroke() { - - $n=strlen($this->iNumber); - for($i=0; $i < $n; ++$i ) { - if( !is_numeric($this->iNumber[$i]) || $this->iNumber[$i]==0 ) { - return false; - } - } - - $dd = new HandDigits(); - $n = strlen($this->iNumber); - $img = @imagecreatetruecolor($n*$dd->iWidth, $dd->iHeight); - if( $img < 1 ) { - return false; - } - $start=0; - for($i=0; $i < $n; ++$i ) { - $size = $dd->digits[$this->iNumber[$i]][0]; - $dimg = imagecreatefromstring(base64_decode($dd->digits[$this->iNumber[$i]][1])); - imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $dd->iHeight); - $start += imagesx($dimg); - } - $resimg = @imagecreatetruecolor($start+4, $dd->iHeight+4); - if( $resimg < 1 ) { - return false; - } - imagecopy($resimg,$img,2,2,0,0,$start, $dd->iHeight); - header("Content-type: image/jpeg"); - imagejpeg($resimg); - return true; - } -} - -?> +digits['6'][0]= 645 ; + $this->digits['6'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. + 'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. + 'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. + 'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. + 'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. + 'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. + 'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; + + //========================================================== + // d2-small.jpg + //========================================================== + $this->digits['2'][0]= 606 ; + $this->digits['2'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. + 'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. + 'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. + 'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. + 'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. + '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. + 'DLZ6f//Z' ; + + //========================================================== + // d9-small.jpg + //========================================================== + $this->digits['9'][0]= 680 ; + $this->digits['9'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. + 'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. + 'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. + 'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. + 'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. + 'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. + 'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. + '1V1//9k=' ; + + //========================================================== + // d5-small.jpg + //========================================================== + $this->digits['5'][0]= 632 ; + $this->digits['5'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. + 'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. + 'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. + 'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. + 'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. + 'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. + '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; + + //========================================================== + // d1-small.jpg + //========================================================== + $this->digits['1'][0]= 646 ; + $this->digits['1'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. + 'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. + 'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. + 'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. + 'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. + 'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. + 'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; + + //========================================================== + // d8-small.jpg + //========================================================== + $this->digits['8'][0]= 694 ; + $this->digits['8'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. + 'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. + 'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. + 'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. + '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. + 'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. + 'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. + 'EylmLHQltptPZKQOBo1FzH//2Q==' ; + + //========================================================== + // d4-small.jpg + //========================================================== + $this->digits['4'][0]= 643 ; + $this->digits['4'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. + 'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. + 'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. + 'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. + 'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. + '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. + 'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; + + //========================================================== + // d7-small.jpg + //========================================================== + $this->digits['7'][0]= 658 ; + $this->digits['7'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. + 'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. + 'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. + '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. + 'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. + '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. + 'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; + + //========================================================== + // d3-small.jpg + //========================================================== + $this->digits['3'][0]= 662 ; + $this->digits['3'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. + 'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. + 'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. + 'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. + 'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. + 'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. + 'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; + } +} + +class AntiSpam { + + var $iNumber=''; + + function __construct($aNumber='') { + $this->iNumber = $aNumber; + } + + function Rand($aLen) { + $d=''; + for($i=0; $i < $aLen; ++$i) { + $d .= rand(1,9); + } + $this->iNumber = $d; + return $d; + } + + function Stroke() { + + $n=strlen($this->iNumber); + for($i=0; $i < $n; ++$i ) { + if( !is_numeric($this->iNumber[$i]) || $this->iNumber[$i]==0 ) { + return false; + } + } + + $dd = new HandDigits(); + $n = strlen($this->iNumber); + $img = @imagecreatetruecolor($n*$dd->iWidth, $dd->iHeight); + if( $img < 1 ) { + return false; + } + $start=0; + for($i=0; $i < $n; ++$i ) { + $size = $dd->digits[$this->iNumber[$i]][0]; + $dimg = imagecreatefromstring(base64_decode($dd->digits[$this->iNumber[$i]][1])); + imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $dd->iHeight); + $start += imagesx($dimg); + } + $resimg = @imagecreatetruecolor($start+4, $dd->iHeight+4); + if( $resimg < 1 ) { + return false; + } + imagecopy($resimg,$img,2,2,0,0,$start, $dd->iHeight); + header("Content-type: image/jpeg"); + imagejpeg($resimg); + return true; + } +} + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_antispam.php b/ext/jpgraph-3.0.7/src/jpgraph_antispam.php index 0a84778..39f0500 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_antispam.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_antispam.php @@ -1,615 +1,615 @@ -chars['j'][0]= 658 ; - $this->chars['j'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGBAf/xAAsEAACAQMDAwMBCQAAAAAAAAAB'. -'AgMEBREAEjEGIUEUUXGBBxMVIiNSYWKC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAGhEAAwADAQAAAAAAAAAAAAAAAAECERIh'. -'Mv/aAAwDAQACEQMRAD8A6veK2st8zRWSyV1dUBfvHaGVI4hknsS7AFv4AyM57ayWbqeS+11xtT2etttwo4YqhEqnQs5bcAfyk4AZ'. -'SOeD441TKRTyingUBG4/ah8j684+dSFzh/BvtaslejMUu9DPQTDnLx4lQ/ONw1TGBm0jdRWqguEMghEisWilgDmNs4Ze+MEEEH40'. -'aUVFTa7JeLjRXu4GjhmnNbSfqFQVlA3rkckOjH/Q99Glmkl0C/Q06pvsvT9vttXHDF6T1KrWbs5gRgQJM+FDlQxPhjpF1XcVq+qe'. -'jEoKiOecXBqh2TDDYIXLKuP6549xk8auI6aJqV45oknWdNswkAIkGMYIxjGO2NR1F0LZY5qkWqkS1xrM0M8lMSJpY+TGrnJiQ577'. -'cEgeNHhi7D3qC3UN69M8tIakRhgrh9o748+eNGtcCiKjjpkQKlMTEg3ZwoxtHHtgfTRpYXArvp//2Q==' ; - - //========================================================== - // lf-small.jpg - //========================================================== - $this->chars['f'][0]= 633 ; - $this->chars['f'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQFBgcC/8QAKxAAAgEDAwMCBQUAAAAAAAAA'. -'AQIDBBEhAAUGEjFBEyIHFFFhoRUzYnGS/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/xAAaEQACAwEBAAAAAAAAAAAAAAAAAQIRMRIh'. -'/9oADAMBAAIRAxEAPwDcnmLoIkiSYsouC3tA++O2lU9WkqVjJ+YdhZLsQI/4/YfQm50kZP0vbmaCSU0SRNIH6sghb9INs3t38dvp'. -'akUuz8x5DwdN5peS1jV1dSipSiVUigIcdQjQ26lIB/c6r3F86SZpE/zCFJaqsihQNhRgdj3Jyfxo0jDSbXHt9Oph9RAoV3qJGltY'. -'HDOxyb/nRpV0D3RXle21m48XraOk3IUSemUaV4g4Zc9ShcDtgff+tQfwvjq34Dtku7buamFqeJKemCCMxKFsEJU+/FrX8d76sEHG'. -'aNItzr4usVNdG3S0rmRYAVwEUmyjyQLZ11x7aF4zs9DQOyzml29I2cLa/pixIHi99DFCtU9dFuLIaijo9qiYPmR2mZmB9thgAHOD'. -'4+mjUrURyrUNMZFEkkIOFuFAbsP9d/OjVIQ6Vh4tP//Z' ; - - //========================================================== - // lb-small.jpg - //========================================================== - $this->chars['b'][0]= 645 ; - $this->chars['b'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYCAwUH/8QAKxAAAQMDAwMDAwUAAAAAAAAA'. -'AQIDBAAFEQYSIRMxUSJBYQcVI2JxgqHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/xAAYEQEBAQEBAAAAAAAAAAAAAAAAATERYf/a'. -'AAwDAQACEQMRAD8A6H95mxNYwLXcX+pCuilSLXJ6YSplaUELjqxwe4IJ5PIPamJ2V0bPcS7+NxCX1cHggAnIP+xSd9RyzHh2m7FQ'. -'Q1CvMNQWTjCt+HFD+PB/Y1fI1PL1HFFt0zaGblFdJQ9cJjpZiqPJUlBAKnPcEpGB5NNRKdrOl1NlgiQol4R2w4Sc5VtGf7opZteo'. -'LhdorjUSM5FnQnlR50NeHQysYxtVxlJHIPgjtRRD3xkaghs6juumdHz4+Y7RVPnt59K2mk7W+fcKWsZ7djTXMkW+xMP3GRJjwIEN'. -'HTG/CWx5wPY8AADx2NYk3SL9wukvUjGobnBkORksIbjdMANozgEqSo8qJPGO/wAVO36IsjUmBIfZfuM7epZk3F9UhSSk5O0K9Kcq'. -'8AcU3UzFuhUSBFud6nRXoz96mqmJZWg7m2dqUNhWBwdqQSP1UU5c/FFCn//Z' ; - - //========================================================== - // d6-small.jpg - //========================================================== - $this->chars['6'][0]= 645 ; - $this->chars['6'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. -'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. -'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. -'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. -'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. -'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. -'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; - - //========================================================== - // lx-small.jpg - //========================================================== - $this->chars['x'][0]= 650 ; - $this->chars['x'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABMDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBgj/xAApEAABAwMDAwQCAwAAAAAAAAAB'. -'AgMEBQYRACFBBxIxFCJRgRNxkcHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAMAwEA'. -'AhEDEQA/AH9t3pKvO14UykVARa/HfAlxlDKXR24V2p3z7RlPwdtMep91uWdRGHWELjuTFFtLvcC4SNznnH+21O7ttiodOq1BvC0E'. -'p9I0lSX2kgqCSklK+5PKCMAng6zV2XRO6u3lSIURtbDRShltlZHa0tW7q/0MeTwnjxq1Jiw2xc9xTLbhSVU5iaXUFfqFFILgJOCd'. -'9Gt3SXabR6REpkL8yo0RpLCFNx1qBCRjOQMHxo0pEr6o3um2LVYpMEpTVqg25lHn08dfcB9kEgfZ1LIFDuawqZRb7aQlLTzqglsg'. -'9wQdveOEqBIB425xqhQuk8qo9UKlPrlRblw2ZBeCSVKW6CcoSrI2AGOT41SKzT4dYtmdS5bIXDZhNoWgbZJ94x8AYT/GkM03oNUc'. -'uKgwqtTZDTMOU0FttqRkoHggnPkEEHRrkJ6t1SlSHYUOc6zHaWrsbQrATk5/vRqK/9k=' ; - - //========================================================== - // d2-small.jpg - //========================================================== - $this->chars['2'][0]= 606 ; - $this->chars['2'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. -'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. -'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. -'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. -'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. -'7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. -'DLZ6f//Z' ; - - //========================================================== - // lm-small.jpg - //========================================================== - $this->chars['m'][0]= 649 ; - $this->chars['m'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAcDBAUCBv/EAC0QAAICAQMCBAMJAAAAAAAA'. -'AAECAwQRAAUSBiETMVFhB2KhFSIyQVJxgZHB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAR'. -'EiEx/9oADAMBAAIRAxEAPwB0MI2lIdgI0Cly3kFXLEn2zx1FDdp7rbpbjUtRWKio3hyxOGQllJzkegX66rQ2qW87Zuk9S5FNVmru'. -'iywyBhjDKTkeXfSr+GRfYtq2KAO32b1BGxAZu0dyJ2DKPTxY1wPddVszycUq2Golq8jRWbcnJWwCVGMjz+VQP50atxMtm2ZUOY4l'. -'4qfUnBP0x/Z0amy4jJm10Tt2yddWasFmfaRfdrlG3UcgArnxKzJ+Fu4DqCMkcgNem2DoWav8PLfTm+FPEkuSNTnqueS5bnHIv6CG'. -'LNjJwM99bm67NB1Ht89KSxNXnr2hNDbiUc47K4KyD2GQMfmMjUnS+7vuIktTqPCaaWCqAMMojPFyw8hyYMQBnAwNJHYGXPTsW9VN'. -'jg2zf50W9zk524GAEihuz+xbIOD82jW5TkjtRPZkTkJ+4VgDhQfuj/f3OjUxl1f/2Q==' ; - - //========================================================== - // lt-small.jpg - //========================================================== - $this->chars['t'][0]= 648 ; - $this->chars['t'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAJxAAAQMDAgYDAQEAAAAAAAAA'. -'AQIDBAUGEQASEyExQVFhIjJxFSP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAP/xAAZEQADAQEBAAAAAAAAAAAAAAAAAREhMUH/2gAM'. -'AwEAAhEDEQA/AO4BLEiEy7uG4IGxxs5IOOx76wd2XYidSp1HoD70240gcNNPbDyI6wQQpaz8E9MczkdhqtbsKYLieDk6WLKmZmmL'. -'Hk7AHVkbkLI+RQc7uRxgkfr1tx2rGu6VbToLVKkhU+kbugGf9WfaknCk5ycaX0zmaa+3JkqvW/CmzojsB9xoF6OoFK0r6HOcEDI0'. -'aefTuKX5ScMdC14HYq8n12zo1DEUcKTGg1Z+hyBwoPBVIiA/VQyOIgedhUCB4WMfXSV3UufVLcTUIqVf26K6mXDbPVRRzKT54iMg'. -'+zjtq6mtsyJjclxpKlUhSXEbkgkqWnBx4+J5e/zU0pZemPvJJQzEPDfQOrwwFY9AZ5eeYPLV6FwhoFYZuigxpkJeIjqAeIoAk9wA'. -'D46EnuD+6Nc1smDNrTlRkxqtMo1vzKhIdYgU9YDqVpISrLhHxSSd21I0aYyqP//Z' ; - - //========================================================== - // li-small.jpg - //========================================================== - $this->chars['i'][0]= 639 ; - $this->chars['i'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAGBP/EACcQAAEEAQMEAgIDAAAAAAAAAAEC'. -'AwQRBQAGEiExQVEHExSBFWFx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMB/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECMRH/2gAMAwEA'. -'AhEDEQA/AE7c+5M9BeRG29t1WUfKFFYW+GvrI7WD3B9g140YD5T36rcErDjbUR6dCBdejsKUpxITXI2FUrooCh70yvxzHyIlMvuK'. -'eVSH7IKEpJoKqu/ahddLryR/aMiO187bsmrWShhp1AZS2XHHrWhNJrzdf7f7GiVcHk3sptmHkJcJ2DIftS2FrKlJPXudWuLGYeQp'. -'t2fmEIckqIZaaKuSGG0lQ4gduRoFRHQ9AOgs2lOJbk9aSUlpjGvAWeSVH2VKq/2dFPw3IjyJe8s281ct3I9UoHJXGiQkD2STrSZ7'. -'Yf8AOl7JTdw5eOCz0jw3+LbYCfA9nz71msb8KMxoTGTw+5srjsipAdDqFBQBIuiOl6KrdYyJMyTCshlw2G3Fr/HiNqNNAqJJUoGl'. -'KND+h47km1bZwsvCbYYjycxIyK1qDv2yEi0hQviK8atKDcy9j//Z' ; - - - //========================================================== - // lp-small.jpg - //========================================================== - $this->chars['p'][0]= 700 ; - $this->chars['p'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAECBAUGB//EAC8QAAEDAwMCBAMJAAAAAAAA'. -'AAECAwQFESEABhIiMRMVUWEHFEEWIzIzcYGRocH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAcEQACAgIDAAAAAAAAAAAAAAAA'. -'AQIxAxESIUH/2gAMAwEAAhEDEQA/AOh703xG21DMeOyqoVNDjSzERiwU6Ep5qtZNycA97HTF13d33KWtmlt9xwkLl1NkXVxIuQgK'. -'wLj+hqBvel0qmbR8GnR22nJNZiLeeKr8nDIT1OLJucX+uPbWom7iocRpafOac5MX1ALltp/Cbi+cJH++utdh+WVNL3PNdNYpdWgx'. -'Y0qmLZSrwJJcQoOJ5XKlJFu4HbJOjVbt+V5nu7eopNRivqcdhK+bFnWwA1Y2AOcgjvj9dGlxy0g5y0xd+hNXoG24C4obizq3HZUh'. -'YHqtRHD06bG/8a0MbbG1mqekxaBSGmgkrcdcitlLfrckZIz7DUatbeFak0tyRLUwzT5vmiGm0cufEkFBJItfkD+59tKmiO12atFa'. -'eQukO3ejUxgENqTcfnE5WbkHiOnJ76N2IqI1DibabptS+zkZhtp90F2Y0S026EkAFK/qL46cXv65NVZDfxHmVCK4DE2/RX/lRFbA'. -'C5LwAyq2EtpHZI7mxPYDRqoctdESimz/2Q==' ; - - //========================================================== - // le-small.jpg - //========================================================== - $this->chars['e'][0]= 700 ; - $this->chars['e'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcB/8QAKhAAAQMCBAUEAwEAAAAAAAAA'. -'AgEDBAURAAYSIQciMTJBE0JRYRQVFoH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERAjFB'. -'/9oADAMBAAIRAxEAPwDTszvhEYCoS80BTm2bCjQRwdAzVe2yopkpJtpRUVfjEIc4V2oMerByg5Ji30oMyS3GeMunK0upfnu09MdJ'. -'p2scTmWnnGfx6HThktgLfKj7xEOqyr7QBbL41LhBzpxbcOru0LKDLdSnOHoaltNqSC4qWL0x9xbJYum69caczSaHmGmTmpDUYn4l'. -'UiqjkynzAVtwV23Ud+X4Ibpa2DCPkjhfUaRO/p8yzpb+YHhUmhbev6ZEll1lvqK3jt2XrbBgp6HVwsK3THpfEubGSoOUyFMpbJmL'. -'Deh6SgOGKti57EuY6l62JMWdJy7k3hg1LkOozEbVm7suQSkTiKtkEfP1pH664Za/QItccgI4bseTHdNxiXHLQ8yVl7V32XyioqL5'. -'TGc1ng6eYs0idczXUZscBBABWgEhEtfKNuUezwPnBhEuj8X2M21z9BR6NUX211Kk/UKKAjuhkPhL7XVf8vtgw7UPJlEyrDWFSYLb'. -'LBNF6qrzG6t0spEu6+fpL7YMXhUndp//2Q==' ; - - //========================================================== - // la-small.jpg - //========================================================== - $this->chars['a'][0]= 730 ; - $this->chars['a'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABoDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwIFAQcCBwAAAAAAAAAB'. -'AgMEBREAEiExQQYHFBUiUXGBE2EyQkNSgpHh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAMBAv/EABkRAAMBAQEAAAAAAAAAAAAAAAAB'. -'IQIRMf/aAAwDAQACEQMRAD8AfdQ1pxjqZMSn0mRUZRYDaklJCE3OawO2ttTxY4hl07qFMVs1Ku02kpPnRGhsAqz8W9T9wDjozq6o'. -'Q1lDrcZLGVcmUoZg0obpufxK3Ftt9ccqB1GgBcmLSqtVEqOZcr6ARm/kbXHt7DEtc7WTJKTJqEWvRKfLqL9QplSjuPtGVYOJKBrm'. -'t+U+n94WGStZzNypmRWqckUKTbixy6jAfxPxHtCgKqFNlU5huK6pLMndSlegG4J45N8aKmTMKQRBsCNMzwB+RbHWHGEAZlPZX2hx'. -'qZIC34ygZoYUbB50JSkFXFhZR9BrpheR4fIbQ6gvurJ7q02bIQTuAOAN8x40HAxRr3TrNRpBmSHVt1KMlTyJTCsqkKAPlSf28W+c'. -'UGaD1c9HSR1HFUh9tJU45EBcAtcC9+P9wqbg8IAto9o81yputrVGpiUkgHKkqUTZI32+cKm1z1tIUgPBBAKQ4UBQH3uL3xmXSXep'. -'HVDtXStE5K5jlPU7PF3Q41+okJFkjgC+3OuNSYiSzHaLtRcW4UDMpLYSCbakDW3thhum5p//2Q==' ; - - //========================================================== - // d9-small.jpg - //========================================================== - $this->chars['9'][0]= 680 ; - $this->chars['9'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. -'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. -'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. -'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. -'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. -'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. -'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. -'1V1//9k=' ; - - //========================================================== - // d5-small.jpg - //========================================================== - $this->chars['5'][0]= 632 ; - $this->chars['5'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. -'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. -'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. -'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. -'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. -'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. -'8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; - - //========================================================== - // d1-small.jpg - //========================================================== - $this->chars['1'][0]= 646 ; - $this->chars['1'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. -'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. -'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. -'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. -'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. -'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. -'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; - - //========================================================== - // ll-small.jpg - //========================================================== - $this->chars['l'][0]= 626 ; - $this->chars['l'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYEBQf/xAArEAACAQIFAwIGAwAAAAAAAAAB'. -'AgMEEQAFBhIhFEFREzEHFSIyYcFxgZH/xAAXAQEAAwAAAAAAAAAAAAAAAAACAAED/8QAGhEAAwEAAwAAAAAAAAAAAAAAAAECMREh'. -'Qf/aAAwDAQACEQMRAD8A15Zfm1VURj1Fp5AqLKv3OARcL4W5Nzx+MLWjdRz5hqXU6TSb6OCr6WghiQbrJ91gOTy1yT5xZ55myZFk'. -'Gb5ozX6Ondm28XYqpQDwu7jEH4c5S2UaDy4xxrLmlUDWzk8XaQ3O49hbj+RiB85HNg8Ee3aqwIqhDuux7G/HHbvzgxEqaWOvy09R'. -'O0o3hjdQoUji20g+fY3wYSM6pJ4Ylr7V+Zz5PSaezHTlTRNWzxySSxt6q1MSkH6AOT2Fu3Aw7RfF/T9DEkLUeawuF2mKSgdWQj2/'. -'q3+fnDZDlqRZzQGaOGcpTOaeR1u8R+ncN3gj94so2jNWHeMNNKzorEX2qp9v3imNPoRE1zpjUtZ09HJmYq5lury0benZeTww23t3'. -'Ivgw+T0yRRyyxIqNfkLcA8jt7YMKcBWn/9k=' ; - - - //========================================================== - // ls-small.jpg - //========================================================== - $this->chars['s'][0]= 701 ; - $this->chars['s'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAMCBAUGB//EACwQAAEEAQIFAgUFAAAAAAAA'. -'AAECAwQFEQAGEhMUITEiYQcjQVFxFRZCUoH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAZEQADAQEBAAAAAAAAAAAAAAAAAQIR'. -'EiH/2gAMAwEAAhEDEQA/APWZMhmFXSJU+SGmWFiQtAWMJQAnJUr8Z+w/OuQk71uZnMsqnbjy9s8st9UMCQ6kZJdZaIHEkZ/JHceN'. -'N3HtizuY1JLrG48yLBSC9UTFKQiY4nACir+wAOOMEe2rm2bTbzlqtE1MyBuZAPybpw85KSfDRJ4Cg+Pl/wC61hJeGjV31VuuKqwr'. -'LGU+whZZK+Rw+oYJAyj3GjS4dZFpZVkqPLktdfMXNcaU2kBC1BIITkdx6c599GlnvPAa3TL2vNvU76n0063acr3YSLCEjpUpUQtW'. -'Dhf14SMEnOc57aZ8Tegm7dbrEQGZt1PeTDgc1PEW3FeXAvyAkZVkeMDOm2G3f3O7Cl/qEuqkQg4lp6CRxraWfUlRUD24kZA741Ko'. -'2k1HvlT3ri2sLOCgtsyJz6XEtBwZPAgJAGQMHUNPWKqWItsqh0UCFVyLeKhyLHQ2TMdHNVj+RKlAnJyfto1FW2ahgjrq6LYTFjjf'. -'lymUOLdWfJyoHA+gA7AAAaNPE3ysJdLT/9k=' ; - - //========================================================== - // lh-small.jpg - //========================================================== - $this->chars['h'][0]= 677 ; - $this->chars['h'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUGB//EACwQAAIBAwMCBQIHAAAAAAAA'. -'AAECAwQFEQAGEiExExQiQVEVggcyU2GRocH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAwQB/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQAC'. -'AyEyMf/aAAwDAQACEQMRAD8A6DZb95q9bmpK6ieOCzNHJTxmE+NMhQ5fr1fLq3Ejvkak2e7ipiFsqb3R0m4qkPPJRiRXenU9VjKE'. -'5JVcA9R7nWc3/BUbfoKTdO3VRXhpjbZ2D8Rwk6RyZH6chB+46m7i2hDYtgA2ePlV2VkuKysoLzzRnlIScZJZeeevvjtrX7LK2rp7'. -'tTwwJ9WjhILDrTKnIdMEDl2+P80aVdJZb1QW+vgqENLPH4sBCDLIwUgnOf4GjVvDnLgUk79T81voqjb8NnuUx8pVRCiEaYUSuynl'. -'jHU9mOfnOoOx6hqz8PrbNdfEkMUXg1LSM3rKOUywJ7YAJ1ZTWmSpvdvlaVTDSUzJAhH5ZJBgv0x2RSAPlz21WXqoet3ba9nuW8n4'. -'Jr6qTPqnUNxSM/f6mPvxA9zqJnExTbR+h0nkhVu1uE8j0UBRQ9PGxBKFjnkAScdsDp10a0lc7z0tI7Y5YYN+5GAf7GjVXF4Icj3f'. -'/9k=' ; - - - //========================================================== - // ld-small.jpg - //========================================================== - $this->chars['d'][0]= 681 ; - $this->chars['d'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFBgH/xAAsEAABAwMEAAQFBQAAAAAAAAAB'. -'AgMEBQYRABIhMQcTI0EUMlFhkRgicaGx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgEA/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECETH/'. -'2gAMAwEAAhEDEQA/ALUhp6h3W/X63UlypbhCY0WMjLqGzwDtPCfv/WtealNpVInuVBBqCogcdbU36YUkAkJWVHG8YPXBxxzxqPcN'. -'YtWyWnIlUeW05VEOAvrCnnSkftK1H5lKJPHsMDoDUWq+KdrSbIqsalVsImiEtLUZ2MU71bcYJWkhZ/36ayLHhi/IXZVOmzKqp5uU'. -'688hTyjuGVEFJKvoQesD86NL2jGZp1EoLDSmk+ZAQ8d7oPzp3YGesFWMfxo1YGvSzLsT9QExVX8phTlMaFOExAJIBGQjJwCcL+/e'. -'rd+W7GuO0Kw05CQ6+ww69Gfdb2kFIKk7DgEkjgnr86rXRa9HuyP8LV4SH0sIBbWFFDiFEgDaocgdkjo8ccay0qw7ut5nyrcviQqC'. -'slsRKo0HwlODkBRzxj2AGoXTtpzIdQ8MbffUChz4NCPRaClAo9Mn6c7T3o13wytmo0K05VIqkiPJbizFiMWs4CTgnIIHOST796NL'. -'Ia1JX//Z' ; - - //========================================================== - // d8-small.jpg - //========================================================== - $this->chars['8'][0]= 694 ; - $this->chars['8'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. -'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. -'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. -'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. -'44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. -'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. -'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. -'EylmLHQltptPZKQOBo1FzH//2Q==' ; - - //========================================================== - // lz-small.jpg - //========================================================== - $this->chars['z'][0]= 690 ; - $this->chars['z'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgAHA//EACsQAAEDAwQBAwIHAAAAAAAAAAEC'. -'AwQFESEABhIxBxMiQVFxCCM0UmGRof/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/EABgRAAMBAQAAAAAAAAAAAAAAAAABEVEC/9oA'. -'DAMBAAIRAxEAPwBTWfLu1KXXZDbM4uewNvLajlwhaCbBAwDe5uehYd3xm6t6bi3jvulwqc7KgxXZZeYQLNLeF73WRg4HEdgfzrSa'. -'P45pNEkznITDc9ypLShtyWhJDJyXC2qxJHZvjoZOjyVv1v8AESt6FFS4ijxvTLbawEApSccrYHJf0+OtJMQ2rNXk7GZMufJgJjTH'. -'Un9M4qzxT7hyCiThIyRnPXWrRvyLElVBUF6vlhl0lwRYCFKcQhAtyWpVhyWTx+w++rUvp4EWjOvbniUOnVatcS43BYDbJSPZyIBw'. -'ejclIx+3Wa+J63T6DQanuGszI0eZVJJV60p0Jum5GEi6le7l0PjvSjyRsaTvJqI1BqhhR46ksuMrQVJcUSEoUbHNr/7o7C8L7eiz'. -'4lLlyJk2cEqW+6V+m0AE9ISLnsj5+O9UhsFK92bZZqb9SRu9p2c4A0OCEqDbYAJSlJwAVZv3fBvbFrg/462btlhuS1RG5nL8pYkq'. -'KrnsKH06I/rVrQKkf//Z' ; - - //========================================================== - // d4-small.jpg - //========================================================== - $this->chars['4'][0]= 643 ; - $this->chars['4'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. -'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. -'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. -'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. -'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. -'27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. -'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; - - //========================================================== - // lv-small.jpg - //========================================================== - $this->chars['v'][0]= 648 ; - $this->chars['v'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAKBAAAQQBAwMEAgMAAAAAAAAA'. -'AQIDBBEFAAYhEzFBEhQiYQdRFTKB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAwD'. -'AQACEQMRAD8A6Ngt1SZ4yrYgrecgTFsFJA9aGwAUrUaF2D2Avjzq6CIjiBPkB9bwQVIkIYIDae/wq+P9N+dY4SGMf+Txlev7KBmY'. -'PoadKRy4zxSgRxaTwO/x09u7KPYnasmHjlsyFZZXt4K23ezjvBpNGgLUrvXfVZyLLbWambiwEbKvvxYAkeotNlIJW2FEJWb7WBda'. -'NSQI0fHYyJjkrjKRDZQwnpQ1vgBIr+w8+a+9GocZr8iKkuY1eXhsKH8U8iZE9BHz6ZHUc48UfSPqzqH3kfeO9kTTDQYGGietpTaO'. -'shyW6AocpHNIrv8AvWzk9BUSdPdYS4BcRlomkhIV6KP0VE39V+tU2wdlRMHtZUB8NuTQ+51X27+Kr46ZPIAFV540D8zeLsJ5LMHa'. -'ubmMBCVJdjx0pRyLoWR4I8aNIQ8BvZMNtMTeUcsptKfc4tC1gAkCyFC+K0aJtf/Z' ; - - //========================================================== - // lk-small.jpg - //========================================================== - $this->chars['k'][0]= 680 ; - $this->chars['k'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBAMH/8QALhAAAQMDAwIEBAcAAAAAAAAA'. -'AQIDBAUREgAGITFBEyIyYQcVUYEUIzNicZHx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEE/8QAGxEAAwACAwAAAAAAAAAAAAAAAAEC'. -'AxESMeH/2gAMAwEAAhEDEQA/APVK/V36dU6NSJDTT8esPLiqfK8S2cCoeTkKvZQ6jm2ldSqKqbu+OgMOvSX3m4UBrLnDlbqiefKl'. -'Nzz2x1m+IwNP27CkJQ7JkR6rCkMJbP5jp8S2CPfkgD6H+dJ6Ca0nerr+64rTNSqMYrg+C9mmOwhVpDfsuxSbi97DmybaoZeQ5jTl'. -'PEp18JTIfeW3kq3ly4H26aNZqvTWZsjFcZTsVtSg0G8Rio+vr2vb7g6NLPRnuXy8F+8kl+obUh4KXJdqSJJQnohlkZqJPYBXh3P+'. -'a4b5Hyp6k1bO7sOotPyXkj9NlwFl0ewstJA9ifrqkVSmET4csoS7UTHXFQ+6SQlskKUMb/tH9ddLVUmS7DqdBqD7U6OsqfS46jzl'. -'hQ5bXb1K9Scuybdxo2OTu92dwSZkWn0Sb8viQWyn8Qq5D6ifSLd0BIv7q0arTBRSKPToMZbi2GWylsvLK148Wue/XRrRjxOpT2R2'. -'k9aP/9k=' ; - - //========================================================== - // lr-small.jpg - //========================================================== - $this->chars['r'][0]= 681 ; - $this->chars['r'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAYCBQMEB//EAC4QAAICAQIFAgMJAQAAAAAA'. -'AAECAwQRBQYAEiExQQdRFGFxEyIyM0JSYoGC8P/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/EABcRAQEBAQAAAAAAAAAAAAAAAAAB'. -'EUH/2gAMAwEAAhEDEQA/AOs0ZdETU54Gt1INSmlPJEsyo7J+jlXPUYBPY9c+eE/dO9tY0a7ren6BVrW7VJTZtW5kZkjXkBSIKveQ'. -'gHp0AAJ4w+q2hVdT2Md0h46+saS4mr3EUK0gWTAB+vQj2PboeL/ZVOqmhaZVjkFmxdC6tctt3tM2G5/7bAx4C4+qxiWwd3prWzKe'. -'r3IBAth5OYxozKsgc8y4GTgnJB9uncdTi6tXq2140rRVM13JMEMAVAg7sMdBjJB/18uDgRO9R2Oo6FX2vShkFzURFUq1whIj+8DI'. -'7EdAFjXv7MeNb0kuStsFEmIaajZaos2fy2Q4VGH7SGxn+Rzw9yMLOm/FzRhZazmOTkP4grYyD3B8j2PTyeFfZ+z7G3BeSS8lmprl'. -'2K2qcnK0Z5S8gPjrgAY8cNEWmq7u23pEos6/Zji+Kd0rLLGWwseA3joeZj/w4OET1g0vlmrWV+ydFnkUxSgsvM4V+YYIwfHz6cHB'. -'ZeKZ1//Z' ; - - //========================================================== - // lg-small.jpg - //========================================================== - $this->chars['g'][0]= 655 ; - $this->chars['g'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCBQYH/8QAJxAAAQQBAwQCAgMAAAAAAAAA'. -'AQIDBBEFAAYhBxIxQRNhcYEiQlH/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EABkRAAMBAQEAAAAAAAAAAAAAAAABAhEhIv/a'. -'AAwDAQACEQMRAD8AayO4t6bq3hmMHtxyLi4OKeKH5jyASiiQCCQeTRNAeB61FrBb+jTGpLO+BMW24EFMhkhpQru8m7B/H70x09Yi'. -'q3nv/vLfwpnJ7UNkqSRbngf2ofWkpXV7brymC2malLfagurjW0aHk89xPJ9cX9aprURHWbYEaMHHEBfwpv8AnXPk+/8AdGqGJOxO'. -'4YbOSxK4y4boIStUWysgkEmxY54r60aOI8oTV9MHtjJwunPUbO46WWo0HLlD8KY4goboFVoquOVEVwLT963WdnxYfT6ZJyz0JvHm'. -'KvtaSkW4tYNVSqKiTwB+fw5n9sY/cuOXCzDDcluyW3Ckd7V+0n0eNZTH9DdouFalHIOJBUhtDki0pNV3UALo81ehG6IdKjPZ6d47'. -'4ywltanVJvuJI+RQs/sHRqy2r003JhsImEc/CUyhxRZBjKV2oJ8eRXNmufPnRo1WIz3DdNn/2Q==' ; - - //========================================================== - // lc-small.jpg - //========================================================== - $this->chars['c'][0]= 629 ; - $this->chars['c'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBwID/8QALRAAAgICAQIEBAYDAAAAAAAA'. -'AQIDBAURACExBhIiQRMVUWEHMkJScYFykaH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAXEQEBAQEAAAAAAAAAAAAAAAAAATER'. -'/9oADAMBAAIRAxEAPwDcoGkmiT4Q8kWvzuPU38D2/v8A1zwrCFayq1qTaFk2H7aJHt05MeMvENzC4upDWkjW9kJXiricAJCigvJN'. -'IB1IVQT5frrv24twPgunk6a288crbklUSJNNdnSTZ2STHHqOP/Eb17njdZtAoqwEvrEiGVyG117/AG6HhyV8H1sljMldoxXTksGC'. -'zV7M0oaWGQOVeGQ92I6EMR22D11w4LmEPjaOL51iL8ssc9Z69zHtZkYCGGeQK0ez2UEoU39wCeX1S/LLiEt+mPSbMLxsGVv2kEjR'. -'305xkaEV/GTULMUT1LD/AAGh8gIZS2jv+vpybb8NMIb0dVLWYWgiiU0vmMphOj6V0TvQI3rfsON1E6dYjGtisa0F1mAWR2NhG0WZ'. -'3Ls3TqNs5Hc9h23w49NWL9K+Q/VD5T/zhwPH/9k=' ; - - //========================================================== - // d7-small.jpg - //========================================================== - $this->chars['7'][0]= 658 ; - $this->chars['7'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. -'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. -'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. -'19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. -'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. -'8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. -'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; - - //========================================================== - // ly-small.jpg - //========================================================== - $this->chars['y'][0]= 672 ; - $this->chars['y'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGBQf/xAArEAABAwMEAQIFBQAAAAAAAAAB'. -'AgMEBREhAAYSEzEHIhQkQVGxQmFxgaH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/xAAeEQEAAgEEAwAAAAAAAAAAAAABABECAxIh'. -'MUGR8P/aAAwDAQACEQMRAD8Ar3tys07dVHohemz5dWQ7fk91MsA3IIRY8rkKFySceTqw3JVV0KhyKw+0C1CQp9aUOFSiAk4AIAvn'. -'76xtz0ioVvbcJ6msx2JtOfZmw1PKI5LQcJNh7UqBKcn6+NRfqPu6s1fYc6GxSJsRfWDUVSGA22ygEckJWSexRNgOP0udXzDKOJ0I'. -'yo62mHm25Sy80l1Z4lSgpQvZRGLgWwPGjTjbchyLH+Ejx22EtJSgO8kki3kADA/nOjWjGzv73CyQZjUWNVp7bNSrj7qJDqflqUlQ'. -'DMds24l3HvcNr3Pi9gME6T9WWVsemdYWswwC2lPta4m5WMA3OdUExCmozUJD6g84ntMjrHIFBTdQz5yLDx/WDNytpwW6nAkViqVe'. -'uvmXdlme6n4dCwlRBKEgA2tj99QG7Ilncp5QqpU31PMsJ6x7A32f6SPxo0hPVCD45oVyKf0MtgeT97/nRrO7UOCFla3tn//Z' ; - - //========================================================== - // d3-small.jpg - //========================================================== - $this->chars['3'][0]= 662 ; - $this->chars['3'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. -'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. -'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. -'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. -'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. -'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. -'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. -'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; - - //========================================================== - // ln-small.jpg - //========================================================== - $this->chars['n'][0]= 643 ; - $this->chars['n'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGwAAAgEFAAAAAAAAAAAAAAAAAAYCAQMEBQf/xAAtEAACAQMCBAUCBwAAAAAA'. -'AAABAgMEBREAIQYSE0EHIjFRcWGRIzIzQoGCwf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAP/EABkRAQEBAQEBAAAAAAAAAAAAAAEA'. -'AhEhUf/aAAwDAQACEQMRAD8A6FR3p7v4oV9rlkMQsjL00RyOss0KkFxnDcrc2PbI1NOJKyTjW+W5OmKeA0UEJx5meRZS2/8AUfbS'. -'LVGS1+K16vCzfiR3GmoqqXGyxz06hWPsFlVMfOmq1iNvE69KjBYo3oJMZ3GKeYYPxg/fW+xzZX1FLQyxwSTcpWNceu4G3+aNSmpY'. -'qmQzzwh2k8yhv2r2H23/AJ0aoy+EWh7I1ntacR3PxDtEzhjWy0wkkIwYmanU5GO6sNh7rrU8AVdTceNbhDXxNHUQvS0tZ3DzwxVA'. -'fB7hj59/XJ08cPWaKj4gvlwSQiG7dCboqvLy9NOmQT9SM7ayJrBa6K5V91hjlWorp4JGUOAglRSiMMDb82/vgaBGTpVvtNUVtyJg'. -'5+WNAh5ZCu/r2+dGrgq0pi0DhmlRsSSAfqMd+b6ZyNu3po1Rk1yNBe3/2Q==' ; - - //========================================================== - // lu-small.jpg - //========================================================== - $this->chars['u'][0]= 671 ; - $this->chars['u'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAJRAAAQQBAwQDAQEAAAAAAAAA'. -'AQIDBBEFAAYhBxMxYRJBURSB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAD/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQARITFBAv/aAAwD'. -'AQACEQMRAD8A6dLkQmJzu3WVtHIqjf0duKFNuBr5UTQ45F1R8/XI1PMmsYoJyjhS9iI7BKHeKjkXZVXqhyLHP+rrHeR1pZlx1W1M'. -'wTiW0ukkrS28nn5fV2SPPFfurHUKQhzYG7pLYKEfyBhaSOS7dG/YCki/uvWn3LPDOJrwa4kyEzOYeakqkpC3Hk0bNePQHgDRpchY'. -'leIZwzUWauKtuPctTSUlCAUmrBHIKuAPV/ujQsmHdm7hya43UbbD3ZVElOQJsdTS6IQaQUqBHCk8E2Pocgam6oYwObHy0Zm0oi45'. -'T1KBPdpV2f0pom/1Ws7cmPazu98Ltvcq3VzRHfehz8a4pirFEKRZo8eQT+eCdWYfS/b+WYnxpbuVcDRMdHcyTqg2fiAfiLoi+Rf+'. -'jT7Xc74HtOYnHyUOh8yWUvKeHhy0CiPVUAPoDRrm+OeznTva6lzsyMjCYbbaiNJjJSWElagD5tRpNUSALFeNGoOCH7Bv/9k=' ; - - //========================================================== - // lw-small.jpg - //========================================================== - $this->chars['w'][0]= 673 ; - $this->chars['w'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYDBAX/xAAtEAACAQMDAgMHBQAAAAAAAAAB'. -'AgMEBREABhIhMRMUQRUiIzJRYZEWNIGx0f/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//EABoRAAICAwAAAAAAAAAAAAAAAAABERIh'. -'MVH/2gAMAwEAAhEDEQA/AHXbV13ZLu6t2/uaa1JijWopVp4XUTKSAXRyc+6ehBGeoPbTSlwpql0K3GneqpZViqUhI5JzGMEZJGeh'. -'GlXfaFILDf7FQzXC426rDLTojs8sLqVkXBGcfKf40twWbdWzZY75R0s90ul3jPtKjVMJDNn4DDp8iEhW+wJ1WZG2KWt3Lv26U1tv'. -'92o7PaYkgYUbqVepYlmUBlIwqnB++O2jTDt/bBtth9jcpvEWNGqalZQryTlmeR8jPct6+mNGmRC4a1U13htzVFItB5nA/cyOUVfp'. -'7oz/ALqitJulYJKuqvFsppHALLFb3cp9FBaXr+O51bq0q6i38KK5PDVAAxSzU6SIpz3Kjjn8jUFoS7uFmut1gq17xLFQ+DxOccj8'. -'Rsn+tVpiyJnqv09YfOXu5AycgZZQEhBZjgDBOOgwO/po0sttWHdNzqLruioa4UwmdaC3kYp4IwSvJlBHKQ4OSe3po0qxM6P/2Q==' ; - - //========================================================== - // lq-small.jpg - //========================================================== - $this->chars['q'][0]= 671 ; - $this->chars['q'][1]= -'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. -'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. -'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcDBAUG/8QAKRAAAQQBBAICAQQDAAAAAAAA'. -'AQIDBBEFAAYSIQcxIlETCBQVgSNBYf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMB'. -'AAIRAxEAPwDT3H5Qz+O3LN2vtrF/y86NYLzzVlAABJITQPv2a/17vXMboz3lDEYWPuafNx7CFrS03+2jpK2bs0CUkUa7pRvrUu63'. -'sr438yv7pLEo4XIK5Kcji0uJUkckm+uQUOVH6GsnyJv7A5vaJwuFdkONLmolgONFH4vioKRXYqyCADXvRMh0yspmZ4jyIEtDTK47'. -'aiA0lQUopBJBI/7X9aNT7amRo228e3a31iO3yUzCcdSPiKAIFdCho0TIswZ7GQlO/hlRxBooih1YXzAoKUkX0LPEBX110dJ7zbuv'. -'AORpO04cIpmxH23FSEIRwKuNnsdk0o31702XhFMKbuRUZJWP8LTQ6HBCuIB+iVWSR2BXuqK93/hDlvGzEphmG3Ml5JpDi1I7TzNA'. -'BYFlPafY+/7LBiv1CYDH4iFDOGySlMR22lFP4wCUpANfL11o1r4bxXlWMNEaE/bqlIbCFl/ANPK5Do/M0VDr2Rf3o0TX/9k=' ; - - - - } -} - -class AntiSpam { - - private $iData=''; - private $iDD=null; - - function __construct($aData='') { - $this->iData = $aData; - $this->iDD = new HandDigits(); - } - - function Set($aData) { - $this->iData = $aData; - } - - function Rand($aLen) { - $d=''; - for($i=0; $i < $aLen; ++$i) { - if( rand(0,9) < 6 ) { - // Digits - $d .= chr( ord('1') + rand(0,8) ); - } - else { - // Letters - do { - $offset = rand(0,25); - } while ( $offset==14 ); - $d .= chr( ord('a') + $offset ); - } - } - $this->iData = $d; - return $d; - } - - function Stroke() { - - $n=strlen($this->iData); - if( $n==0 ) { - return false; - } - - for($i=0; $i < $n; ++$i ) { - if( $this->iData[$i]==='0' || strtolower($this->iData[$i])==='o') { - return false; - } - } - - $img = @imagecreatetruecolor($n*$this->iDD->iWidth, $this->iDD->iHeight); - if( $img < 1 ) { - return false; - } - - $start=0; - for($i=0; $i < $n; ++$i ) { - $dimg = imagecreatefromstring(base64_decode($this->iDD->chars[strtolower($this->iData[$i])][1])); - imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $this->iDD->iHeight); - $start += imagesx($dimg); - } - $resimg = @imagecreatetruecolor($start+4, $this->iDD->iHeight+4); - if( $resimg < 1 ) { - return false; - } - - imagecopy($resimg,$img,2,2,0,0,$start, $this->iDD->iHeight); - header("Content-type: image/jpeg"); - imagejpeg($resimg); - return true; - } -} - -?> +chars['j'][0]= 658 ; + $this->chars['j'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGBAf/xAAsEAACAQMDAwMBCQAAAAAAAAAB'. +'AgMEBREAEjEGIUEUUXGBBxMVIiNSYWKC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAGhEAAwADAQAAAAAAAAAAAAAAAAECERIh'. +'Mv/aAAwDAQACEQMRAD8A6veK2st8zRWSyV1dUBfvHaGVI4hknsS7AFv4AyM57ayWbqeS+11xtT2etttwo4YqhEqnQs5bcAfyk4AZ'. +'SOeD441TKRTyingUBG4/ah8j684+dSFzh/BvtaslejMUu9DPQTDnLx4lQ/ONw1TGBm0jdRWqguEMghEisWilgDmNs4Ze+MEEEH40'. +'aUVFTa7JeLjRXu4GjhmnNbSfqFQVlA3rkckOjH/Q99Glmkl0C/Q06pvsvT9vttXHDF6T1KrWbs5gRgQJM+FDlQxPhjpF1XcVq+qe'. +'jEoKiOecXBqh2TDDYIXLKuP6549xk8auI6aJqV45oknWdNswkAIkGMYIxjGO2NR1F0LZY5qkWqkS1xrM0M8lMSJpY+TGrnJiQ577'. +'cEgeNHhi7D3qC3UN69M8tIakRhgrh9o748+eNGtcCiKjjpkQKlMTEg3ZwoxtHHtgfTRpYXArvp//2Q==' ; + + //========================================================== + // lf-small.jpg + //========================================================== + $this->chars['f'][0]= 633 ; + $this->chars['f'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQFBgcC/8QAKxAAAgEDAwMCBQUAAAAAAAAA'. +'AQIDBBEhAAUGEjFBEyIHFFFhoRUzYnGS/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/xAAaEQACAwEBAAAAAAAAAAAAAAAAAQIRMRIh'. +'/9oADAMBAAIRAxEAPwDcnmLoIkiSYsouC3tA++O2lU9WkqVjJ+YdhZLsQI/4/YfQm50kZP0vbmaCSU0SRNIH6sghb9INs3t38dvp'. +'akUuz8x5DwdN5peS1jV1dSipSiVUigIcdQjQ26lIB/c6r3F86SZpE/zCFJaqsihQNhRgdj3Jyfxo0jDSbXHt9Oph9RAoV3qJGltY'. +'HDOxyb/nRpV0D3RXle21m48XraOk3IUSemUaV4g4Zc9ShcDtgff+tQfwvjq34Dtku7buamFqeJKemCCMxKFsEJU+/FrX8d76sEHG'. +'aNItzr4usVNdG3S0rmRYAVwEUmyjyQLZ11x7aF4zs9DQOyzml29I2cLa/pixIHi99DFCtU9dFuLIaijo9qiYPmR2mZmB9thgAHOD'. +'4+mjUrURyrUNMZFEkkIOFuFAbsP9d/OjVIQ6Vh4tP//Z' ; + + //========================================================== + // lb-small.jpg + //========================================================== + $this->chars['b'][0]= 645 ; + $this->chars['b'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYCAwUH/8QAKxAAAQMDAwMDAwUAAAAAAAAA'. +'AQIDBAAFEQYSIRMxUSJBYQcVI2JxgqHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/xAAYEQEBAQEBAAAAAAAAAAAAAAAAATERYf/a'. +'AAwDAQACEQMRAD8A6H95mxNYwLXcX+pCuilSLXJ6YSplaUELjqxwe4IJ5PIPamJ2V0bPcS7+NxCX1cHggAnIP+xSd9RyzHh2m7FQ'. +'Q1CvMNQWTjCt+HFD+PB/Y1fI1PL1HFFt0zaGblFdJQ9cJjpZiqPJUlBAKnPcEpGB5NNRKdrOl1NlgiQol4R2w4Sc5VtGf7opZteo'. +'LhdorjUSM5FnQnlR50NeHQysYxtVxlJHIPgjtRRD3xkaghs6juumdHz4+Y7RVPnt59K2mk7W+fcKWsZ7djTXMkW+xMP3GRJjwIEN'. +'HTG/CWx5wPY8AADx2NYk3SL9wukvUjGobnBkORksIbjdMANozgEqSo8qJPGO/wAVO36IsjUmBIfZfuM7epZk3F9UhSSk5O0K9Kcq'. +'8AcU3UzFuhUSBFud6nRXoz96mqmJZWg7m2dqUNhWBwdqQSP1UU5c/FFCn//Z' ; + + //========================================================== + // d6-small.jpg + //========================================================== + $this->chars['6'][0]= 645 ; + $this->chars['6'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. +'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. +'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. +'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. +'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. +'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. +'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; + + //========================================================== + // lx-small.jpg + //========================================================== + $this->chars['x'][0]= 650 ; + $this->chars['x'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABMDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBgj/xAApEAABAwMDAwQCAwAAAAAAAAAB'. +'AgMEBQYRACFBBxIxFCJRgRNxkcHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAMAwEA'. +'AhEDEQA/AH9t3pKvO14UykVARa/HfAlxlDKXR24V2p3z7RlPwdtMep91uWdRGHWELjuTFFtLvcC4SNznnH+21O7ttiodOq1BvC0E'. +'p9I0lSX2kgqCSklK+5PKCMAng6zV2XRO6u3lSIURtbDRShltlZHa0tW7q/0MeTwnjxq1Jiw2xc9xTLbhSVU5iaXUFfqFFILgJOCd'. +'9Gt3SXabR6REpkL8yo0RpLCFNx1qBCRjOQMHxo0pEr6o3um2LVYpMEpTVqg25lHn08dfcB9kEgfZ1LIFDuawqZRb7aQlLTzqglsg'. +'9wQdveOEqBIB425xqhQuk8qo9UKlPrlRblw2ZBeCSVKW6CcoSrI2AGOT41SKzT4dYtmdS5bIXDZhNoWgbZJ94x8AYT/GkM03oNUc'. +'uKgwqtTZDTMOU0FttqRkoHggnPkEEHRrkJ6t1SlSHYUOc6zHaWrsbQrATk5/vRqK/9k=' ; + + //========================================================== + // d2-small.jpg + //========================================================== + $this->chars['2'][0]= 606 ; + $this->chars['2'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. +'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. +'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. +'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. +'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. +'7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. +'DLZ6f//Z' ; + + //========================================================== + // lm-small.jpg + //========================================================== + $this->chars['m'][0]= 649 ; + $this->chars['m'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAcDBAUCBv/EAC0QAAICAQMCBAMJAAAAAAAA'. +'AAECAwQRAAUSBiETMVFhB2KhFSIyQVJxgZHB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAR'. +'EiEx/9oADAMBAAIRAxEAPwB0MI2lIdgI0Cly3kFXLEn2zx1FDdp7rbpbjUtRWKio3hyxOGQllJzkegX66rQ2qW87Zuk9S5FNVmru'. +'iywyBhjDKTkeXfSr+GRfYtq2KAO32b1BGxAZu0dyJ2DKPTxY1wPddVszycUq2Golq8jRWbcnJWwCVGMjz+VQP50atxMtm2ZUOY4l'. +'4qfUnBP0x/Z0amy4jJm10Tt2yddWasFmfaRfdrlG3UcgArnxKzJ+Fu4DqCMkcgNem2DoWav8PLfTm+FPEkuSNTnqueS5bnHIv6CG'. +'LNjJwM99bm67NB1Ht89KSxNXnr2hNDbiUc47K4KyD2GQMfmMjUnS+7vuIktTqPCaaWCqAMMojPFyw8hyYMQBnAwNJHYGXPTsW9VN'. +'jg2zf50W9zk524GAEihuz+xbIOD82jW5TkjtRPZkTkJ+4VgDhQfuj/f3OjUxl1f/2Q==' ; + + //========================================================== + // lt-small.jpg + //========================================================== + $this->chars['t'][0]= 648 ; + $this->chars['t'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAJxAAAQMDAgYDAQEAAAAAAAAA'. +'AQIDBAUGEQASEyExQVFhIjJxFSP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAP/xAAZEQADAQEBAAAAAAAAAAAAAAAAAREhMUH/2gAM'. +'AwEAAhEDEQA/AO4BLEiEy7uG4IGxxs5IOOx76wd2XYidSp1HoD70240gcNNPbDyI6wQQpaz8E9MczkdhqtbsKYLieDk6WLKmZmmL'. +'Hk7AHVkbkLI+RQc7uRxgkfr1tx2rGu6VbToLVKkhU+kbugGf9WfaknCk5ycaX0zmaa+3JkqvW/CmzojsB9xoF6OoFK0r6HOcEDI0'. +'aefTuKX5ScMdC14HYq8n12zo1DEUcKTGg1Z+hyBwoPBVIiA/VQyOIgedhUCB4WMfXSV3UufVLcTUIqVf26K6mXDbPVRRzKT54iMg'. +'+zjtq6mtsyJjclxpKlUhSXEbkgkqWnBx4+J5e/zU0pZemPvJJQzEPDfQOrwwFY9AZ5eeYPLV6FwhoFYZuigxpkJeIjqAeIoAk9wA'. +'D46EnuD+6Nc1smDNrTlRkxqtMo1vzKhIdYgU9YDqVpISrLhHxSSd21I0aYyqP//Z' ; + + //========================================================== + // li-small.jpg + //========================================================== + $this->chars['i'][0]= 639 ; + $this->chars['i'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAGBP/EACcQAAEEAQMEAgIDAAAAAAAAAAEC'. +'AwQRBQAGEiExQVEHExSBFWFx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMB/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECMRH/2gAMAwEA'. +'AhEDEQA/AE7c+5M9BeRG29t1WUfKFFYW+GvrI7WD3B9g140YD5T36rcErDjbUR6dCBdejsKUpxITXI2FUrooCh70yvxzHyIlMvuK'. +'eVSH7IKEpJoKqu/ahddLryR/aMiO187bsmrWShhp1AZS2XHHrWhNJrzdf7f7GiVcHk3sptmHkJcJ2DIftS2FrKlJPXudWuLGYeQp'. +'t2fmEIckqIZaaKuSGG0lQ4gduRoFRHQ9AOgs2lOJbk9aSUlpjGvAWeSVH2VKq/2dFPw3IjyJe8s281ct3I9UoHJXGiQkD2STrSZ7'. +'Yf8AOl7JTdw5eOCz0jw3+LbYCfA9nz71msb8KMxoTGTw+5srjsipAdDqFBQBIuiOl6KrdYyJMyTCshlw2G3Fr/HiNqNNAqJJUoGl'. +'KND+h47km1bZwsvCbYYjycxIyK1qDv2yEi0hQviK8atKDcy9j//Z' ; + + + //========================================================== + // lp-small.jpg + //========================================================== + $this->chars['p'][0]= 700 ; + $this->chars['p'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAECBAUGB//EAC8QAAEDAwMCBAMJAAAAAAAA'. +'AAECAwQFESEABhIiMRMVUWEHFEEWIzIzcYGRocH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAcEQACAgIDAAAAAAAAAAAAAAAA'. +'AQIxAxESIUH/2gAMAwEAAhEDEQA/AOh703xG21DMeOyqoVNDjSzERiwU6Ep5qtZNycA97HTF13d33KWtmlt9xwkLl1NkXVxIuQgK'. +'wLj+hqBvel0qmbR8GnR22nJNZiLeeKr8nDIT1OLJucX+uPbWom7iocRpafOac5MX1ALltp/Cbi+cJH++utdh+WVNL3PNdNYpdWgx'. +'Y0qmLZSrwJJcQoOJ5XKlJFu4HbJOjVbt+V5nu7eopNRivqcdhK+bFnWwA1Y2AOcgjvj9dGlxy0g5y0xd+hNXoG24C4obizq3HZUh'. +'YHqtRHD06bG/8a0MbbG1mqekxaBSGmgkrcdcitlLfrckZIz7DUatbeFak0tyRLUwzT5vmiGm0cufEkFBJItfkD+59tKmiO12atFa'. +'eQukO3ejUxgENqTcfnE5WbkHiOnJ76N2IqI1DibabptS+zkZhtp90F2Y0S026EkAFK/qL46cXv65NVZDfxHmVCK4DE2/RX/lRFbA'. +'C5LwAyq2EtpHZI7mxPYDRqoctdESimz/2Q==' ; + + //========================================================== + // le-small.jpg + //========================================================== + $this->chars['e'][0]= 700 ; + $this->chars['e'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcB/8QAKhAAAQMCBAUEAwEAAAAAAAAA'. +'AgEDBAURAAYSIQciMTJBE0JRYRQVFoH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERAjFB'. +'/9oADAMBAAIRAxEAPwDTszvhEYCoS80BTm2bCjQRwdAzVe2yopkpJtpRUVfjEIc4V2oMerByg5Ji30oMyS3GeMunK0upfnu09MdJ'. +'p2scTmWnnGfx6HThktgLfKj7xEOqyr7QBbL41LhBzpxbcOru0LKDLdSnOHoaltNqSC4qWL0x9xbJYum69caczSaHmGmTmpDUYn4l'. +'UiqjkynzAVtwV23Ud+X4Ibpa2DCPkjhfUaRO/p8yzpb+YHhUmhbev6ZEll1lvqK3jt2XrbBgp6HVwsK3THpfEubGSoOUyFMpbJmL'. +'Deh6SgOGKti57EuY6l62JMWdJy7k3hg1LkOozEbVm7suQSkTiKtkEfP1pH664Za/QItccgI4bseTHdNxiXHLQ8yVl7V32XyioqL5'. +'TGc1ng6eYs0idczXUZscBBABWgEhEtfKNuUezwPnBhEuj8X2M21z9BR6NUX211Kk/UKKAjuhkPhL7XVf8vtgw7UPJlEyrDWFSYLb'. +'LBNF6qrzG6t0spEu6+fpL7YMXhUndp//2Q==' ; + + //========================================================== + // la-small.jpg + //========================================================== + $this->chars['a'][0]= 730 ; + $this->chars['a'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABoDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwIFAQcCBwAAAAAAAAAB'. +'AgMEBREAEiExQQYHFBUiUXGBE2EyQkNSgpHh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAMBAv/EABkRAAMBAQEAAAAAAAAAAAAAAAAB'. +'IQIRMf/aAAwDAQACEQMRAD8AfdQ1pxjqZMSn0mRUZRYDaklJCE3OawO2ttTxY4hl07qFMVs1Ku02kpPnRGhsAqz8W9T9wDjozq6o'. +'Q1lDrcZLGVcmUoZg0obpufxK3Ftt9ccqB1GgBcmLSqtVEqOZcr6ARm/kbXHt7DEtc7WTJKTJqEWvRKfLqL9QplSjuPtGVYOJKBrm'. +'t+U+n94WGStZzNypmRWqckUKTbixy6jAfxPxHtCgKqFNlU5huK6pLMndSlegG4J45N8aKmTMKQRBsCNMzwB+RbHWHGEAZlPZX2hx'. +'qZIC34ygZoYUbB50JSkFXFhZR9BrpheR4fIbQ6gvurJ7q02bIQTuAOAN8x40HAxRr3TrNRpBmSHVt1KMlTyJTCsqkKAPlSf28W+c'. +'UGaD1c9HSR1HFUh9tJU45EBcAtcC9+P9wqbg8IAto9o81yputrVGpiUkgHKkqUTZI32+cKm1z1tIUgPBBAKQ4UBQH3uL3xmXSXep'. +'HVDtXStE5K5jlPU7PF3Q41+okJFkjgC+3OuNSYiSzHaLtRcW4UDMpLYSCbakDW3thhum5p//2Q==' ; + + //========================================================== + // d9-small.jpg + //========================================================== + $this->chars['9'][0]= 680 ; + $this->chars['9'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. +'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. +'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. +'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. +'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. +'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. +'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. +'1V1//9k=' ; + + //========================================================== + // d5-small.jpg + //========================================================== + $this->chars['5'][0]= 632 ; + $this->chars['5'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. +'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. +'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. +'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. +'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. +'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. +'8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; + + //========================================================== + // d1-small.jpg + //========================================================== + $this->chars['1'][0]= 646 ; + $this->chars['1'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. +'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. +'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. +'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. +'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. +'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. +'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; + + //========================================================== + // ll-small.jpg + //========================================================== + $this->chars['l'][0]= 626 ; + $this->chars['l'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYEBQf/xAArEAACAQIFAwIGAwAAAAAAAAAB'. +'AgMEEQAFBhIhFEFREzEHFSIyYcFxgZH/xAAXAQEAAwAAAAAAAAAAAAAAAAACAAED/8QAGhEAAwEAAwAAAAAAAAAAAAAAAAECMREh'. +'Qf/aAAwDAQACEQMRAD8A15Zfm1VURj1Fp5AqLKv3OARcL4W5Nzx+MLWjdRz5hqXU6TSb6OCr6WghiQbrJ91gOTy1yT5xZ55myZFk'. +'Gb5ozX6Ondm28XYqpQDwu7jEH4c5S2UaDy4xxrLmlUDWzk8XaQ3O49hbj+RiB85HNg8Ee3aqwIqhDuux7G/HHbvzgxEqaWOvy09R'. +'O0o3hjdQoUji20g+fY3wYSM6pJ4Ylr7V+Zz5PSaezHTlTRNWzxySSxt6q1MSkH6AOT2Fu3Aw7RfF/T9DEkLUeawuF2mKSgdWQj2/'. +'q3+fnDZDlqRZzQGaOGcpTOaeR1u8R+ncN3gj94so2jNWHeMNNKzorEX2qp9v3imNPoRE1zpjUtZ09HJmYq5lury0benZeTww23t3'. +'Ivgw+T0yRRyyxIqNfkLcA8jt7YMKcBWn/9k=' ; + + + //========================================================== + // ls-small.jpg + //========================================================== + $this->chars['s'][0]= 701 ; + $this->chars['s'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAMCBAUGB//EACwQAAEEAQIFAgUFAAAAAAAA'. +'AAECAwQFEQAGEhMUITEiYQcjQVFxFRZCUoH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAZEQADAQEBAAAAAAAAAAAAAAAAAQIR'. +'EiH/2gAMAwEAAhEDEQA/APWZMhmFXSJU+SGmWFiQtAWMJQAnJUr8Z+w/OuQk71uZnMsqnbjy9s8st9UMCQ6kZJdZaIHEkZ/JHceN'. +'N3HtizuY1JLrG48yLBSC9UTFKQiY4nACir+wAOOMEe2rm2bTbzlqtE1MyBuZAPybpw85KSfDRJ4Cg+Pl/wC61hJeGjV31VuuKqwr'. +'LGU+whZZK+Rw+oYJAyj3GjS4dZFpZVkqPLktdfMXNcaU2kBC1BIITkdx6c599GlnvPAa3TL2vNvU76n0063acr3YSLCEjpUpUQtW'. +'Dhf14SMEnOc57aZ8Tegm7dbrEQGZt1PeTDgc1PEW3FeXAvyAkZVkeMDOm2G3f3O7Cl/qEuqkQg4lp6CRxraWfUlRUD24kZA741Ko'. +'2k1HvlT3ri2sLOCgtsyJz6XEtBwZPAgJAGQMHUNPWKqWItsqh0UCFVyLeKhyLHQ2TMdHNVj+RKlAnJyfto1FW2ahgjrq6LYTFjjf'. +'lymUOLdWfJyoHA+gA7AAAaNPE3ysJdLT/9k=' ; + + //========================================================== + // lh-small.jpg + //========================================================== + $this->chars['h'][0]= 677 ; + $this->chars['h'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUGB//EACwQAAIBAwMCBQIHAAAAAAAA'. +'AAECAwQFEQAGEiExExQiQVEVggcyU2GRocH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAwQB/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQAC'. +'AyEyMf/aAAwDAQACEQMRAD8A6DZb95q9bmpK6ieOCzNHJTxmE+NMhQ5fr1fLq3Ejvkak2e7ipiFsqb3R0m4qkPPJRiRXenU9VjKE'. +'5JVcA9R7nWc3/BUbfoKTdO3VRXhpjbZ2D8Rwk6RyZH6chB+46m7i2hDYtgA2ePlV2VkuKysoLzzRnlIScZJZeeevvjtrX7LK2rp7'. +'tTwwJ9WjhILDrTKnIdMEDl2+P80aVdJZb1QW+vgqENLPH4sBCDLIwUgnOf4GjVvDnLgUk79T81voqjb8NnuUx8pVRCiEaYUSuynl'. +'jHU9mOfnOoOx6hqz8PrbNdfEkMUXg1LSM3rKOUywJ7YAJ1ZTWmSpvdvlaVTDSUzJAhH5ZJBgv0x2RSAPlz21WXqoet3ba9nuW8n4'. +'Jr6qTPqnUNxSM/f6mPvxA9zqJnExTbR+h0nkhVu1uE8j0UBRQ9PGxBKFjnkAScdsDp10a0lc7z0tI7Y5YYN+5GAf7GjVXF4Icj3f'. +'/9k=' ; + + + //========================================================== + // ld-small.jpg + //========================================================== + $this->chars['d'][0]= 681 ; + $this->chars['d'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFBgH/xAAsEAABAwMEAAQFBQAAAAAAAAAB'. +'AgMEBQYRABIhMQcTI0EUMlFhkRgicaGx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgEA/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECETH/'. +'2gAMAwEAAhEDEQA/ALUhp6h3W/X63UlypbhCY0WMjLqGzwDtPCfv/WtealNpVInuVBBqCogcdbU36YUkAkJWVHG8YPXBxxzxqPcN'. +'YtWyWnIlUeW05VEOAvrCnnSkftK1H5lKJPHsMDoDUWq+KdrSbIqsalVsImiEtLUZ2MU71bcYJWkhZ/36ayLHhi/IXZVOmzKqp5uU'. +'688hTyjuGVEFJKvoQesD86NL2jGZp1EoLDSmk+ZAQ8d7oPzp3YGesFWMfxo1YGvSzLsT9QExVX8phTlMaFOExAJIBGQjJwCcL+/e'. +'rd+W7GuO0Kw05CQ6+ww69Gfdb2kFIKk7DgEkjgnr86rXRa9HuyP8LV4SH0sIBbWFFDiFEgDaocgdkjo8ccay0qw7ut5nyrcviQqC'. +'slsRKo0HwlODkBRzxj2AGoXTtpzIdQ8MbffUChz4NCPRaClAo9Mn6c7T3o13wytmo0K05VIqkiPJbizFiMWs4CTgnIIHOST796NL'. +'Ia1JX//Z' ; + + //========================================================== + // d8-small.jpg + //========================================================== + $this->chars['8'][0]= 694 ; + $this->chars['8'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. +'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. +'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. +'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. +'44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. +'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. +'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. +'EylmLHQltptPZKQOBo1FzH//2Q==' ; + + //========================================================== + // lz-small.jpg + //========================================================== + $this->chars['z'][0]= 690 ; + $this->chars['z'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgAHA//EACsQAAEDAwQBAwIHAAAAAAAAAAEC'. +'AwQFESEABhIxBxMiQVFxCCM0UmGRof/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/EABgRAAMBAQAAAAAAAAAAAAAAAAABEVEC/9oA'. +'DAMBAAIRAxEAPwBTWfLu1KXXZDbM4uewNvLajlwhaCbBAwDe5uehYd3xm6t6bi3jvulwqc7KgxXZZeYQLNLeF73WRg4HEdgfzrSa'. +'P45pNEkznITDc9ypLShtyWhJDJyXC2qxJHZvjoZOjyVv1v8AESt6FFS4ijxvTLbawEApSccrYHJf0+OtJMQ2rNXk7GZMufJgJjTH'. +'Un9M4qzxT7hyCiThIyRnPXWrRvyLElVBUF6vlhl0lwRYCFKcQhAtyWpVhyWTx+w++rUvp4EWjOvbniUOnVatcS43BYDbJSPZyIBw'. +'ejclIx+3Wa+J63T6DQanuGszI0eZVJJV60p0Jum5GEi6le7l0PjvSjyRsaTvJqI1BqhhR46ksuMrQVJcUSEoUbHNr/7o7C8L7eiz'. +'4lLlyJk2cEqW+6V+m0AE9ISLnsj5+O9UhsFK92bZZqb9SRu9p2c4A0OCEqDbYAJSlJwAVZv3fBvbFrg/462btlhuS1RG5nL8pYkq'. +'KrnsKH06I/rVrQKkf//Z' ; + + //========================================================== + // d4-small.jpg + //========================================================== + $this->chars['4'][0]= 643 ; + $this->chars['4'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. +'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. +'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. +'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. +'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. +'27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. +'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; + + //========================================================== + // lv-small.jpg + //========================================================== + $this->chars['v'][0]= 648 ; + $this->chars['v'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAKBAAAQQBAwMEAgMAAAAAAAAA'. +'AQIDBBEFAAYhEzFBEhQiYQdRFTKB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAwD'. +'AQACEQMRAD8A6Ngt1SZ4yrYgrecgTFsFJA9aGwAUrUaF2D2Avjzq6CIjiBPkB9bwQVIkIYIDae/wq+P9N+dY4SGMf+Txlev7KBmY'. +'PoadKRy4zxSgRxaTwO/x09u7KPYnasmHjlsyFZZXt4K23ezjvBpNGgLUrvXfVZyLLbWambiwEbKvvxYAkeotNlIJW2FEJWb7WBda'. +'NSQI0fHYyJjkrjKRDZQwnpQ1vgBIr+w8+a+9GocZr8iKkuY1eXhsKH8U8iZE9BHz6ZHUc48UfSPqzqH3kfeO9kTTDQYGGietpTaO'. +'shyW6AocpHNIrv8AvWzk9BUSdPdYS4BcRlomkhIV6KP0VE39V+tU2wdlRMHtZUB8NuTQ+51X27+Kr46ZPIAFV540D8zeLsJ5LMHa'. +'ubmMBCVJdjx0pRyLoWR4I8aNIQ8BvZMNtMTeUcsptKfc4tC1gAkCyFC+K0aJtf/Z' ; + + //========================================================== + // lk-small.jpg + //========================================================== + $this->chars['k'][0]= 680 ; + $this->chars['k'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBAMH/8QALhAAAQMDAwIEBAcAAAAAAAAA'. +'AQIDBAUREgAGITFBEyIyYQcVUYEUIzNicZHx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEE/8QAGxEAAwACAwAAAAAAAAAAAAAAAAEC'. +'AxESMeH/2gAMAwEAAhEDEQA/APVK/V36dU6NSJDTT8esPLiqfK8S2cCoeTkKvZQ6jm2ldSqKqbu+OgMOvSX3m4UBrLnDlbqiefKl'. +'Nzz2x1m+IwNP27CkJQ7JkR6rCkMJbP5jp8S2CPfkgD6H+dJ6Ca0nerr+64rTNSqMYrg+C9mmOwhVpDfsuxSbi97DmybaoZeQ5jTl'. +'PEp18JTIfeW3kq3ly4H26aNZqvTWZsjFcZTsVtSg0G8Rio+vr2vb7g6NLPRnuXy8F+8kl+obUh4KXJdqSJJQnohlkZqJPYBXh3P+'. +'a4b5Hyp6k1bO7sOotPyXkj9NlwFl0ewstJA9ifrqkVSmET4csoS7UTHXFQ+6SQlskKUMb/tH9ddLVUmS7DqdBqD7U6OsqfS46jzl'. +'hQ5bXb1K9Scuybdxo2OTu92dwSZkWn0Sb8viQWyn8Qq5D6ifSLd0BIv7q0arTBRSKPToMZbi2GWylsvLK148Wue/XRrRjxOpT2R2'. +'k9aP/9k=' ; + + //========================================================== + // lr-small.jpg + //========================================================== + $this->chars['r'][0]= 681 ; + $this->chars['r'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAYCBQMEB//EAC4QAAICAQIFAgMJAQAAAAAA'. +'AAECAwQRBQYAEiExQQdRFGFxEyIyM0JSYoGC8P/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/EABcRAQEBAQAAAAAAAAAAAAAAAAAB'. +'EUH/2gAMAwEAAhEDEQA/AOs0ZdETU54Gt1INSmlPJEsyo7J+jlXPUYBPY9c+eE/dO9tY0a7ren6BVrW7VJTZtW5kZkjXkBSIKveQ'. +'gHp0AAJ4w+q2hVdT2Md0h46+saS4mr3EUK0gWTAB+vQj2PboeL/ZVOqmhaZVjkFmxdC6tctt3tM2G5/7bAx4C4+qxiWwd3prWzKe'. +'r3IBAth5OYxozKsgc8y4GTgnJB9uncdTi6tXq2140rRVM13JMEMAVAg7sMdBjJB/18uDgRO9R2Oo6FX2vShkFzURFUq1whIj+8DI'. +'7EdAFjXv7MeNb0kuStsFEmIaajZaos2fy2Q4VGH7SGxn+Rzw9yMLOm/FzRhZazmOTkP4grYyD3B8j2PTyeFfZ+z7G3BeSS8lmprl'. +'2K2qcnK0Z5S8gPjrgAY8cNEWmq7u23pEos6/Zji+Kd0rLLGWwseA3joeZj/w4OET1g0vlmrWV+ydFnkUxSgsvM4V+YYIwfHz6cHB'. +'ZeKZ1//Z' ; + + //========================================================== + // lg-small.jpg + //========================================================== + $this->chars['g'][0]= 655 ; + $this->chars['g'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCBQYH/8QAJxAAAQQBAwQCAgMAAAAAAAAA'. +'AQIDBBEFAAYhBxIxQRNhcYEiQlH/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EABkRAAMBAQEAAAAAAAAAAAAAAAABAhEhIv/a'. +'AAwDAQACEQMRAD8AayO4t6bq3hmMHtxyLi4OKeKH5jyASiiQCCQeTRNAeB61FrBb+jTGpLO+BMW24EFMhkhpQru8m7B/H70x09Yi'. +'q3nv/vLfwpnJ7UNkqSRbngf2ofWkpXV7brymC2malLfagurjW0aHk89xPJ9cX9aprURHWbYEaMHHEBfwpv8AnXPk+/8AdGqGJOxO'. +'4YbOSxK4y4boIStUWysgkEmxY54r60aOI8oTV9MHtjJwunPUbO46WWo0HLlD8KY4goboFVoquOVEVwLT963WdnxYfT6ZJyz0JvHm'. +'KvtaSkW4tYNVSqKiTwB+fw5n9sY/cuOXCzDDcluyW3Ckd7V+0n0eNZTH9DdouFalHIOJBUhtDki0pNV3UALo81ehG6IdKjPZ6d47'. +'4ywltanVJvuJI+RQs/sHRqy2r003JhsImEc/CUyhxRZBjKV2oJ8eRXNmufPnRo1WIz3DdNn/2Q==' ; + + //========================================================== + // lc-small.jpg + //========================================================== + $this->chars['c'][0]= 629 ; + $this->chars['c'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBwID/8QALRAAAgICAQIEBAYDAAAAAAAA'. +'AQIDBAURACExBhIiQRMVUWEHMkJScYFykaH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAXEQEBAQEAAAAAAAAAAAAAAAAAATER'. +'/9oADAMBAAIRAxEAPwDcoGkmiT4Q8kWvzuPU38D2/v8A1zwrCFayq1qTaFk2H7aJHt05MeMvENzC4upDWkjW9kJXiricAJCigvJN'. +'IB1IVQT5frrv24twPgunk6a288crbklUSJNNdnSTZ2STHHqOP/Eb17njdZtAoqwEvrEiGVyG117/AG6HhyV8H1sljMldoxXTksGC'. +'zV7M0oaWGQOVeGQ92I6EMR22D11w4LmEPjaOL51iL8ssc9Z69zHtZkYCGGeQK0ez2UEoU39wCeX1S/LLiEt+mPSbMLxsGVv2kEjR'. +'305xkaEV/GTULMUT1LD/AAGh8gIZS2jv+vpybb8NMIb0dVLWYWgiiU0vmMphOj6V0TvQI3rfsON1E6dYjGtisa0F1mAWR2NhG0WZ'. +'3Ls3TqNs5Hc9h23w49NWL9K+Q/VD5T/zhwPH/9k=' ; + + //========================================================== + // d7-small.jpg + //========================================================== + $this->chars['7'][0]= 658 ; + $this->chars['7'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. +'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. +'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. +'19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. +'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. +'8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. +'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; + + //========================================================== + // ly-small.jpg + //========================================================== + $this->chars['y'][0]= 672 ; + $this->chars['y'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGBQf/xAArEAABAwMEAQIFBQAAAAAAAAAB'. +'AgMEBREhAAYSEzEHIhQkQVGxQmFxgaH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/xAAeEQEAAgEEAwAAAAAAAAAAAAABABECAxIh'. +'MUGR8P/aAAwDAQACEQMRAD8Ar3tys07dVHohemz5dWQ7fk91MsA3IIRY8rkKFySceTqw3JVV0KhyKw+0C1CQp9aUOFSiAk4AIAvn'. +'76xtz0ioVvbcJ6msx2JtOfZmw1PKI5LQcJNh7UqBKcn6+NRfqPu6s1fYc6GxSJsRfWDUVSGA22ygEckJWSexRNgOP0udXzDKOJ0I'. +'yo62mHm25Sy80l1Z4lSgpQvZRGLgWwPGjTjbchyLH+Ejx22EtJSgO8kki3kADA/nOjWjGzv73CyQZjUWNVp7bNSrj7qJDqflqUlQ'. +'DMds24l3HvcNr3Pi9gME6T9WWVsemdYWswwC2lPta4m5WMA3OdUExCmozUJD6g84ntMjrHIFBTdQz5yLDx/WDNytpwW6nAkViqVe'. +'uvmXdlme6n4dCwlRBKEgA2tj99QG7Ilncp5QqpU31PMsJ6x7A32f6SPxo0hPVCD45oVyKf0MtgeT97/nRrO7UOCFla3tn//Z' ; + + //========================================================== + // d3-small.jpg + //========================================================== + $this->chars['3'][0]= 662 ; + $this->chars['3'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. +'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. +'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. +'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. +'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. +'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. +'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; + + //========================================================== + // ln-small.jpg + //========================================================== + $this->chars['n'][0]= 643 ; + $this->chars['n'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGwAAAgEFAAAAAAAAAAAAAAAAAAYCAQMEBQf/xAAtEAACAQMCBAUCBwAAAAAA'. +'AAABAgMEBREAIQYSE0EHIjFRcWGRIzIzQoGCwf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAP/EABkRAQEBAQEBAAAAAAAAAAAAAAEA'. +'AhEhUf/aAAwDAQACEQMRAD8A6FR3p7v4oV9rlkMQsjL00RyOss0KkFxnDcrc2PbI1NOJKyTjW+W5OmKeA0UEJx5meRZS2/8AUfbS'. +'LVGS1+K16vCzfiR3GmoqqXGyxz06hWPsFlVMfOmq1iNvE69KjBYo3oJMZ3GKeYYPxg/fW+xzZX1FLQyxwSTcpWNceu4G3+aNSmpY'. +'qmQzzwh2k8yhv2r2H23/AJ0aoy+EWh7I1ntacR3PxDtEzhjWy0wkkIwYmanU5GO6sNh7rrU8AVdTceNbhDXxNHUQvS0tZ3DzwxVA'. +'fB7hj59/XJ08cPWaKj4gvlwSQiG7dCboqvLy9NOmQT9SM7ayJrBa6K5V91hjlWorp4JGUOAglRSiMMDb82/vgaBGTpVvtNUVtyJg'. +'5+WNAh5ZCu/r2+dGrgq0pi0DhmlRsSSAfqMd+b6ZyNu3po1Rk1yNBe3/2Q==' ; + + //========================================================== + // lu-small.jpg + //========================================================== + $this->chars['u'][0]= 671 ; + $this->chars['u'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAJRAAAQQBAwQDAQEAAAAAAAAA'. +'AQIDBBEFAAYhBxMxYRJBURSB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAD/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQARITFBAv/aAAwD'. +'AQACEQMRAD8A6dLkQmJzu3WVtHIqjf0duKFNuBr5UTQ45F1R8/XI1PMmsYoJyjhS9iI7BKHeKjkXZVXqhyLHP+rrHeR1pZlx1W1M'. +'wTiW0ukkrS28nn5fV2SPPFfurHUKQhzYG7pLYKEfyBhaSOS7dG/YCki/uvWn3LPDOJrwa4kyEzOYeakqkpC3Hk0bNePQHgDRpchY'. +'leIZwzUWauKtuPctTSUlCAUmrBHIKuAPV/ujQsmHdm7hya43UbbD3ZVElOQJsdTS6IQaQUqBHCk8E2Pocgam6oYwObHy0Zm0oi45'. +'T1KBPdpV2f0pom/1Ws7cmPazu98Ltvcq3VzRHfehz8a4pirFEKRZo8eQT+eCdWYfS/b+WYnxpbuVcDRMdHcyTqg2fiAfiLoi+Rf+'. +'jT7Xc74HtOYnHyUOh8yWUvKeHhy0CiPVUAPoDRrm+OeznTva6lzsyMjCYbbaiNJjJSWElagD5tRpNUSALFeNGoOCH7Bv/9k=' ; + + //========================================================== + // lw-small.jpg + //========================================================== + $this->chars['w'][0]= 673 ; + $this->chars['w'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYDBAX/xAAtEAACAQMDAgMHBQAAAAAAAAAB'. +'AgMEBREABhIhMRMUQRUiIzJRYZEWNIGx0f/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//EABoRAAICAwAAAAAAAAAAAAAAAAABERIh'. +'MVH/2gAMAwEAAhEDEQA/AHXbV13ZLu6t2/uaa1JijWopVp4XUTKSAXRyc+6ehBGeoPbTSlwpql0K3GneqpZViqUhI5JzGMEZJGeh'. +'GlXfaFILDf7FQzXC426rDLTojs8sLqVkXBGcfKf40twWbdWzZY75R0s90ul3jPtKjVMJDNn4DDp8iEhW+wJ1WZG2KWt3Lv26U1tv'. +'92o7PaYkgYUbqVepYlmUBlIwqnB++O2jTDt/bBtth9jcpvEWNGqalZQryTlmeR8jPct6+mNGmRC4a1U13htzVFItB5nA/cyOUVfp'. +'7oz/ALqitJulYJKuqvFsppHALLFb3cp9FBaXr+O51bq0q6i38KK5PDVAAxSzU6SIpz3Kjjn8jUFoS7uFmut1gq17xLFQ+DxOccj8'. +'Rsn+tVpiyJnqv09YfOXu5AycgZZQEhBZjgDBOOgwO/po0sttWHdNzqLruioa4UwmdaC3kYp4IwSvJlBHKQ4OSe3po0qxM6P/2Q==' ; + + //========================================================== + // lq-small.jpg + //========================================================== + $this->chars['q'][0]= 671 ; + $this->chars['q'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcDBAUG/8QAKRAAAQQBBAICAQQDAAAAAAAA'. +'AQIDBBEFAAYSIQcxIlETCBQVgSNBYf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMB'. +'AAIRAxEAPwDT3H5Qz+O3LN2vtrF/y86NYLzzVlAABJITQPv2a/17vXMboz3lDEYWPuafNx7CFrS03+2jpK2bs0CUkUa7pRvrUu63'. +'sr438yv7pLEo4XIK5Kcji0uJUkckm+uQUOVH6GsnyJv7A5vaJwuFdkONLmolgONFH4vioKRXYqyCADXvRMh0yspmZ4jyIEtDTK47'. +'aiA0lQUopBJBI/7X9aNT7amRo228e3a31iO3yUzCcdSPiKAIFdCho0TIswZ7GQlO/hlRxBooih1YXzAoKUkX0LPEBX110dJ7zbuv'. +'AORpO04cIpmxH23FSEIRwKuNnsdk0o31702XhFMKbuRUZJWP8LTQ6HBCuIB+iVWSR2BXuqK93/hDlvGzEphmG3Ml5JpDi1I7TzNA'. +'BYFlPafY+/7LBiv1CYDH4iFDOGySlMR22lFP4wCUpANfL11o1r4bxXlWMNEaE/bqlIbCFl/ANPK5Do/M0VDr2Rf3o0TX/9k=' ; + + + + } +} + +class AntiSpam { + + private $iData=''; + private $iDD=null; + + function __construct($aData='') { + $this->iData = $aData; + $this->iDD = new HandDigits(); + } + + function Set($aData) { + $this->iData = $aData; + } + + function Rand($aLen) { + $d=''; + for($i=0; $i < $aLen; ++$i) { + if( rand(0,9) < 6 ) { + // Digits + $d .= chr( ord('1') + rand(0,8) ); + } + else { + // Letters + do { + $offset = rand(0,25); + } while ( $offset==14 ); + $d .= chr( ord('a') + $offset ); + } + } + $this->iData = $d; + return $d; + } + + function Stroke() { + + $n=strlen($this->iData); + if( $n==0 ) { + return false; + } + + for($i=0; $i < $n; ++$i ) { + if( $this->iData[$i]==='0' || strtolower($this->iData[$i])==='o') { + return false; + } + } + + $img = @imagecreatetruecolor($n*$this->iDD->iWidth, $this->iDD->iHeight); + if( $img < 1 ) { + return false; + } + + $start=0; + for($i=0; $i < $n; ++$i ) { + $dimg = imagecreatefromstring(base64_decode($this->iDD->chars[strtolower($this->iData[$i])][1])); + imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $this->iDD->iHeight); + $start += imagesx($dimg); + } + $resimg = @imagecreatetruecolor($start+4, $this->iDD->iHeight+4); + if( $resimg < 1 ) { + return false; + } + + imagecopy($resimg,$img,2,2,0,0,$start, $this->iDD->iHeight); + header("Content-type: image/jpeg"); + imagejpeg($resimg); + return true; + } +} + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_bar.php b/ext/jpgraph-3.0.7/src/jpgraph_bar.php index 10a5ddf..9d61a8e 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_bar.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_bar.php @@ -1,1136 +1,1136 @@ -numpoints; - } - - //--------------- - // PUBLIC METHODS - - // Set a drop shadow for the bar (or rather an "up-right" shadow) - function SetShadow($aColor="black",$aHSize=3,$aVSize=3,$aShow=true) { - $this->bar_shadow=$aShow; - $this->bar_shadow_color=$aColor; - $this->bar_shadow_vsize=$aVSize; - $this->bar_shadow_hsize=$aHSize; - - // Adjust the value margin to compensate for shadow - $this->value->margin += $aVSize; - } - - // DEPRECATED use SetYBase instead - function SetYMin($aYStartValue) { - //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead."); - $this->ybase=$aYStartValue; - } - - // Specify the base value for the bars - function SetYBase($aYStartValue) { - $this->ybase=$aYStartValue; - } - - // The method will take the specified pattern anre - // return a pattern index that corresponds to the original - // patterm being rotated 90 degreees. This is needed when plottin - // Horizontal bars - function RotatePattern($aPat,$aRotate=true) { - $rotate = array(1 => 2, 2 => 1, 3 => 3, 4 => 5, 5 => 4, 6 => 6, 7 => 7, 8 => 8); - if( $aRotate ) { - return $rotate[$aPat]; - } - else { - return $aPat; - } - } - - function Legend($graph) { - if( $this->grad && $this->legend!="" && !$this->fill ) { - $color=array($this->grad_fromcolor,$this->grad_tocolor); - // In order to differentiate between gradients and cooors specified as an RGB triple - $graph->legend->Add($this->legend,$color,"",-$this->grad_style, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - elseif( $this->legend!="" && ($this->iPattern > -1 || is_array($this->iPattern)) ) { - if( is_array($this->iPattern) ) { - $p1 = $this->RotatePattern( $this->iPattern[0], $graph->img->a == 90 ); - $p2 = $this->iPatternColor[0]; - $p3 = $this->iPatternDensity[0]; - } - else { - $p1 = $this->RotatePattern( $this->iPattern, $graph->img->a == 90 ); - $p2 = $this->iPatternColor; - $p3 = $this->iPatternDensity; - } - if( $p3 < 90 ) $p3 += 5; - $color = array($p1,$p2,$p3,$this->fill_color); - // A kludge: Too mark that we add a pattern we use a type value of < 100 - $graph->legend->Add($this->legend,$color,"",-101, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - elseif( $this->fill_color && $this->legend!="" ) { - if( is_array($this->fill_color) ) { - $graph->legend->Add($this->legend,$this->fill_color[0],"",0, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - else { - $graph->legend->Add($this->legend,$this->fill_color,"",0, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - } - } - - // Gets called before any axis are stroked - function PreStrokeAdjust($graph) { - parent::PreStrokeAdjust($graph); - - // If we are using a log Y-scale we want the base to be at the - // minimum Y-value unless the user have specifically set some other - // value than the default. - if( substr($graph->axtype,-3,3)=="log" && $this->ybase==0 ) - $this->ybase = $graph->yaxis->scale->GetMinVal(); - - // For a "text" X-axis scale we will adjust the - // display of the bars a little bit. - if( substr($graph->axtype,0,3)=="tex" ) { - // Position the ticks between the bars - $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); - - // Center the bars - if( $this->abswidth > -1 ) { - $graph->SetTextScaleAbsCenterOff($this->abswidth); - } - else { - if( $this->align == "center" ) - $graph->SetTextScaleOff(0.5-$this->width/2); - elseif( $this->align == "right" ) - $graph->SetTextScaleOff(1-$this->width); - } - } - elseif( ($this instanceof AccBarPlot) || ($this instanceof GroupBarPlot) ) { - // We only set an absolute width for linear and int scale - // for text scale the width will be set to a fraction of - // the majstep width. - if( $this->abswidth == -1 ) { - // Not set - // set width to a visuable sensible default - $this->abswidth = $graph->img->plotwidth/(2*$this->numpoints); - } - } - } - - function Min() { - $m = parent::Min(); - if( $m[1] >= $this->ybase ) $m[1] = $this->ybase; - return $m; - } - - function Max() { - $m = parent::Max(); - if( $m[1] <= $this->ybase ) $m[1] = $this->ybase; - return $m; - } - - // Specify width as fractions of the major stepo size - function SetWidth($aWidth) { - if( $aWidth > 1 ) { - // Interpret this as absolute width - $this->abswidth=$aWidth; - } - else { - $this->width=$aWidth; - } - } - - // Specify width in absolute pixels. If specified this - // overrides SetWidth() - function SetAbsWidth($aWidth) { - $this->abswidth=$aWidth; - } - - function SetAlign($aAlign) { - $this->align=$aAlign; - } - - function SetNoFill() { - $this->grad = false; - $this->fill_color=false; - $this->fill=false; - } - - function SetFillColor($aColor) { - // Do an extra error check if the color is specified as an RGB array triple - // In that case convert it to a hex string since it will otherwise be - // interpretated as an array of colors for each individual bar. - - $aColor = RGB::tryHexConversion($aColor); - $this->fill = true ; - $this->fill_color=$aColor; - - } - - function SetFillGradient($aFromColor,$aToColor=null,$aStyle=null) { - $this->grad = true; - $this->grad_fromcolor = $aFromColor; - $this->grad_tocolor = $aToColor; - $this->grad_style = $aStyle; - } - - function SetValuePos($aPos) { - $this->valuepos = $aPos; - } - - function SetPattern($aPattern, $aColor='black'){ - if( is_array($aPattern) ) { - $n = count($aPattern); - $this->iPattern = array(); - $this->iPatternDensity = array(); - if( is_array($aColor) ) { - $this->iPatternColor = array(); - if( count($aColor) != $n ) { - JpGraphError::RaiseL(2001);//('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()'); - } - } - else { - $this->iPatternColor = $aColor; - } - for( $i=0; $i < $n; ++$i ) { - $this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]); - if( is_array($aColor) ) { - $this->iPatternColor[$i] = $aColor[$i]; - } - } - } - else { - $this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity); - $this->iPatternColor = $aColor; - } - } - - function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){ - switch( $aPattern ) { - case PATTERN_DIAG1: - $aPatternValue= 1; - $aDensity = 92; - break; - case PATTERN_DIAG2: - $aPatternValue= 1; - $aDensity = 78; - break; - case PATTERN_DIAG3: - $aPatternValue= 2; - $aDensity = 92; - break; - case PATTERN_DIAG4: - $aPatternValue= 2; - $aDensity = 78; - break; - case PATTERN_CROSS1: - $aPatternValue= 8; - $aDensity = 90; - break; - case PATTERN_CROSS2: - $aPatternValue= 8; - $aDensity = 78; - break; - case PATTERN_CROSS3: - $aPatternValue= 8; - $aDensity = 65; - break; - case PATTERN_CROSS4: - $aPatternValue= 7; - $aDensity = 90; - break; - case PATTERN_STRIPE1: - $aPatternValue= 5; - $aDensity = 94; - break; - case PATTERN_STRIPE2: - $aPatternValue= 5; - $aDensity = 85; - break; - default: - JpGraphError::RaiseL(2002); - //('Unknown pattern specified in call to BarPlot::SetPattern()'); - } - } - - function Stroke($img,$xscale,$yscale) { - - $numpoints = count($this->coords[0]); - if( isset($this->coords[1]) ) { - if( count($this->coords[1])!=$numpoints ) { - JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); - //"Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints"); - } - else { - $exist_x = true; - } - } - else { - $exist_x = false; - } - - - $numbars=count($this->coords[0]); - - // Use GetMinVal() instead of scale[0] directly since in the case - // of log scale we get a correct value. Log scales will have negative - // values for values < 1 while still not representing negative numbers. - if( $yscale->GetMinVal() >= 0 ) - $zp=$yscale->scale_abs[0]; - else { - $zp=$yscale->Translate(0); - } - - if( $this->abswidth > -1 ) { - $abswidth=$this->abswidth; - } - else { - $abswidth=round($this->width*$xscale->scale_factor,0); - } - - // Count pontetial pattern array to avoid doing the count for each iteration - if( is_array($this->iPattern) ) { - $np = count($this->iPattern); - } - - $grad = null; - for($i=0; $i < $numbars; ++$i) { - - // If value is NULL, or 0 then don't draw a bar at all - if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' ) - continue; - - if( $exist_x ) { - $x=$this->coords[1][$i]; - } - else { - $x=$i; - } - - $x=$xscale->Translate($x); - - // Comment Note: This confuses the positioning when using acc together with - // grouped bars. Workaround for fixing #191 - /* - if( !$xscale->textscale ) { - if($this->align=="center") - $x -= $abswidth/2; - elseif($this->align=="right") - $x -= $abswidth; - } - */ - // Stroke fill color and fill gradient - $pts=array( - $x,$zp, - $x,$yscale->Translate($this->coords[0][$i]), - $x+$abswidth,$yscale->Translate($this->coords[0][$i]), - $x+$abswidth,$zp); - if( $this->grad ) { - if( $grad === null ) { - $grad = new Gradient($img); - } - if( is_array($this->grad_fromcolor) ) { - // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array - // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be - // an array to specify both (from, to style) for each individual bar. The way to know the difference is - // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB - // triple. - $ng = count($this->grad_fromcolor); - if( $ng === 3 ) { - if( is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256 ) { - // RGB Triple - $fromcolor = $this->grad_fromcolor; - $tocolor = $this->grad_tocolor; - $style = $this->grad_style; - } - else { - $fromcolor = $this->grad_fromcolor[$i % $ng][0]; - $tocolor = $this->grad_fromcolor[$i % $ng][1]; - $style = $this->grad_fromcolor[$i % $ng][2]; - } - } - else { - $fromcolor = $this->grad_fromcolor[$i % $ng][0]; - $tocolor = $this->grad_fromcolor[$i % $ng][1]; - $style = $this->grad_fromcolor[$i % $ng][2]; - } - $grad->FilledRectangle($pts[2],$pts[3], - $pts[6],$pts[7], - $fromcolor,$tocolor,$style); - } - else { - $grad->FilledRectangle($pts[2],$pts[3], - $pts[6],$pts[7], - $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); - } - } - elseif( !empty($this->fill_color) ) { - if(is_array($this->fill_color)) { - $img->PushColor($this->fill_color[$i % count($this->fill_color)]); - } else { - $img->PushColor($this->fill_color); - } - $img->FilledPolygon($pts); - $img->PopColor(); - } - - - // Remember value of this bar - $val=$this->coords[0][$i]; - - if( !empty($val) && !is_numeric($val) ) { - JpGraphError::RaiseL(2004,$i,$val); - //'All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\''); - } - - // Determine the shadow - if( $this->bar_shadow && $val != 0) { - - $ssh = $this->bar_shadow_hsize; - $ssv = $this->bar_shadow_vsize; - // Create points to create a "upper-right" shadow - if( $val > 0 ) { - $sp[0]=$pts[6]; $sp[1]=$pts[7]; - $sp[2]=$pts[4]; $sp[3]=$pts[5]; - $sp[4]=$pts[2]; $sp[5]=$pts[3]; - $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; - $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; - $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; - } - elseif( $val < 0 ) { - $sp[0]=$pts[4]; $sp[1]=$pts[5]; - $sp[2]=$pts[6]; $sp[3]=$pts[7]; - $sp[4]=$pts[0]; $sp[5]=$pts[1]; - $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; - $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; - $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; - } - if( is_array($this->bar_shadow_color) ) { - $numcolors = count($this->bar_shadow_color); - if( $numcolors == 0 ) { - JpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.'); - } - $img->PushColor($this->bar_shadow_color[$i % $numcolors]); - } - else { - $img->PushColor($this->bar_shadow_color); - } - $img->FilledPolygon($sp); - $img->PopColor(); - } - - // Stroke the pattern - if( is_array($this->iPattern) ) { - $f = new RectPatternFactory(); - if( is_array($this->iPatternColor) ) { - $pcolor = $this->iPatternColor[$i % $np]; - } - else { - $pcolor = $this->iPatternColor; - } - $prect = $f->Create($this->iPattern[$i % $np],$pcolor,1); - $prect->SetDensity($this->iPatternDensity[$i % $np]); - - if( $val < 0 ) { - $rx = $pts[0]; - $ry = $pts[1]; - } - else { - $rx = $pts[2]; - $ry = $pts[3]; - } - $width = abs($pts[4]-$pts[0])+1; - $height = abs($pts[1]-$pts[3])+1; - $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); - $prect->Stroke($img); - } - else { - if( $this->iPattern > -1 ) { - $f = new RectPatternFactory(); - $prect = $f->Create($this->iPattern,$this->iPatternColor,1); - $prect->SetDensity($this->iPatternDensity); - if( $val < 0 ) { - $rx = $pts[0]; - $ry = $pts[1]; - } - else { - $rx = $pts[2]; - $ry = $pts[3]; - } - $width = abs($pts[4]-$pts[0])+1; - $height = abs($pts[1]-$pts[3])+1; - $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); - $prect->Stroke($img); - } - } - - // Stroke the outline of the bar - if( is_array($this->color) ) { - $img->SetColor($this->color[$i % count($this->color)]); - } - else { - $img->SetColor($this->color); - } - - $pts[] = $pts[0]; - $pts[] = $pts[1]; - - if( $this->weight > 0 ) { - $img->SetLineWeight($this->weight); - $img->Polygon($pts); - } - - // Determine how to best position the values of the individual bars - $x=$pts[2]+($pts[4]-$pts[2])/2; - $this->value->SetMargin(5); - - if( $this->valuepos=='top' ) { - $y=$pts[3]; - if( $img->a === 90 ) { - if( $val < 0 ) { - $this->value->SetAlign('right','center'); - } - else { - $this->value->SetAlign('left','center'); - } - - } - else { - if( $val < 0 ) { - $this->value->SetMargin(-5); - $y=$pts[1]; - $this->value->SetAlign('center','bottom'); - } - else { - $this->value->SetAlign('center','bottom'); - } - - } - $this->value->Stroke($img,$val,$x,$y); - } - elseif( $this->valuepos=='max' ) { - $y=$pts[3]; - if( $img->a === 90 ) { - if( $val < 0 ) - $this->value->SetAlign('left','center'); - else - $this->value->SetAlign('right','center'); - } - else { - if( $val < 0 ) { - $this->value->SetAlign('center','bottom'); - } - else { - $this->value->SetAlign('center','top'); - } - } - $this->value->SetMargin(-5); - $this->value->Stroke($img,$val,$x,$y); - } - elseif( $this->valuepos=='center' ) { - $y = ($pts[3] + $pts[1])/2; - $this->value->SetAlign('center','center'); - $this->value->SetMargin(0); - $this->value->Stroke($img,$val,$x,$y); - } - elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) { - $y=$pts[1]; - if( $img->a === 90 ) { - if( $val < 0 ) - $this->value->SetAlign('right','center'); - else - $this->value->SetAlign('left','center'); - } - $this->value->SetMargin(3); - $this->value->Stroke($img,$val,$x,$y); - } - else { - JpGraphError::RaiseL(2006,$this->valuepos); - //'Unknown position for values on bars :'.$this->valuepos); - } - // Create the client side image map - $rpts = $img->ArrRotate($pts); - $csimcoord=round($rpts[0]).", ".round($rpts[1]); - for( $j=1; $j < 4; ++$j){ - $csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]); - } - if( !empty($this->csimtargets[$i]) ) { - $this->csimareas .= 'csimareas .= " href=\"".htmlentities($this->csimtargets[$i])."\""; - - if( !empty($this->csimwintargets[$i]) ) { - $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; - } - - $sval=''; - if( !empty($this->csimalts[$i]) ) { - $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); - $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; - } - $this->csimareas .= " />\n"; - } - } - return true; - } -} // Class - -//=================================================== -// CLASS GroupBarPlot -// Description: Produce grouped bar plots -//=================================================== -class GroupBarPlot extends BarPlot { - private $plots, $nbrplots=0; - //--------------- - // CONSTRUCTOR - function GroupBarPlot($plots) { - $this->width=0.7; - $this->plots = $plots; - $this->nbrplots = count($plots); - if( $this->nbrplots < 1 ) { - JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.'); - } - for($i=0; $i < $this->nbrplots; ++$i ) { - if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { - JpGraphError::RaiseL(2008,$i);//("Group bar plot element nbr $i is undefined or empty."); - } - } - $this->numpoints = $plots[0]->numpoints; - $this->width=0.7; - } - - //--------------- - // PUBLIC METHODS - function Legend($graph) { - $n = count($this->plots); - for($i=0; $i < $n; ++$i) { - $c = get_class($this->plots[$i]); - if( !($this->plots[$i] instanceof BarPlot) ) { - JpGraphError::RaiseL(2009,$c); - //('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')'); - } - $this->plots[$i]->DoLegend($graph); - } - } - - function Min() { - list($xmin,$ymin) = $this->plots[0]->Min(); - $n = count($this->plots); - for($i=0; $i < $n; ++$i) { - list($xm,$ym) = $this->plots[$i]->Min(); - $xmin = max($xmin,$xm); - $ymin = min($ymin,$ym); - } - return array($xmin,$ymin); - } - - function Max() { - list($xmax,$ymax) = $this->plots[0]->Max(); - $n = count($this->plots); - for($i=0; $i < $n; ++$i) { - list($xm,$ym) = $this->plots[$i]->Max(); - $xmax = max($xmax,$xm); - $ymax = max($ymax,$ym); - } - return array($xmax,$ymax); - } - - function GetCSIMareas() { - $n = count($this->plots); - $csimareas=''; - for($i=0; $i < $n; ++$i) { - $csimareas .= $this->plots[$i]->csimareas; - } - return $csimareas; - } - - // Stroke all the bars next to each other - function Stroke($img,$xscale,$yscale) { - $tmp=$xscale->off; - $n = count($this->plots); - $subwidth = $this->width/$this->nbrplots ; - - for( $i=0; $i < $n; ++$i ) { - $this->plots[$i]->ymin=$this->ybase; - $this->plots[$i]->SetWidth($subwidth); - - // If the client have used SetTextTickInterval() then - // major_step will be > 1 and the positioning will fail. - // If we assume it is always one the positioning will work - // fine with a text scale but this will not work with - // arbitrary linear scale - $xscale->off = $tmp+$i*round($xscale->scale_factor* $subwidth); - $this->plots[$i]->Stroke($img,$xscale,$yscale); - } - $xscale->off=$tmp; - } -} // Class - -//=================================================== -// CLASS AccBarPlot -// Description: Produce accumulated bar plots -//=================================================== -class AccBarPlot extends BarPlot { - private $plots=null,$nbrplots=0; - //--------------- - // CONSTRUCTOR - function __construct($plots) { - $this->plots = $plots; - $this->nbrplots = count($plots); - if( $this->nbrplots < 1 ) { - JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.'); - } - for($i=0; $i < $this->nbrplots; ++$i ) { - if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { - JpGraphError::RaiseL(2011,$i);//("Acc bar plot element nbr $i is undefined or empty."); - } - } - - // We can only allow individual plost which do not have specified X-positions - for($i=0; $i < $this->nbrplots; ++$i ) { - if( !empty($this->plots[$i]->coords[1]) ) { - JpGraphError::RaiseL(2015); - //'Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-positions.'); - } - } - - // Use 0 weight by default which means that the individual bar - // weights will be used per part n the accumulated bar - $this->SetWeight(0); - - $this->numpoints = $plots[0]->numpoints; - $this->value = new DisplayValue(); - } - - //--------------- - // PUBLIC METHODS - function Legend($graph) { - $n = count($this->plots); - for( $i=$n-1; $i >= 0; --$i ) { - $c = get_class($this->plots[$i]); - if( !($this->plots[$i] instanceof BarPlot) ) { - JpGraphError::RaiseL(2012,$c); - //('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')'); - } - $this->plots[$i]->DoLegend($graph); - } - } - - function Max() { - list($xmax) = $this->plots[0]->Max(); - $nmax=0; - for($i=0; $i < count($this->plots); ++$i) { - $n = count($this->plots[$i]->coords[0]); - $nmax = max($nmax,$n); - list($x) = $this->plots[$i]->Max(); - $xmax = max($xmax,$x); - } - for( $i = 0; $i < $nmax; $i++ ) { - // Get y-value for bar $i by adding the - // individual bars from all the plots added. - // It would be wrong to just add the - // individual plots max y-value since that - // would in most cases give to large y-value. - $y=0; - if( !isset($this->plots[0]->coords[0][$i]) ) { - JpGraphError::RaiseL(2014); - } - if( $this->plots[0]->coords[0][$i] > 0 ) - $y=$this->plots[0]->coords[0][$i]; - for( $j = 1; $j < $this->nbrplots; $j++ ) { - if( !isset($this->plots[$j]->coords[0][$i]) ) { - JpGraphError::RaiseL(2014); - } - if( $this->plots[$j]->coords[0][$i] > 0 ) - $y += $this->plots[$j]->coords[0][$i]; - } - $ymax[$i] = $y; - } - $ymax = max($ymax); - - // Bar always start at baseline - if( $ymax <= $this->ybase ) - $ymax = $this->ybase; - return array($xmax,$ymax); - } - - function Min() { - $nmax=0; - list($xmin,$ysetmin) = $this->plots[0]->Min(); - for($i=0; $i < count($this->plots); ++$i) { - $n = count($this->plots[$i]->coords[0]); - $nmax = max($nmax,$n); - list($x,$y) = $this->plots[$i]->Min(); - $xmin = Min($xmin,$x); - $ysetmin = Min($y,$ysetmin); - } - for( $i = 0; $i < $nmax; $i++ ) { - // Get y-value for bar $i by adding the - // individual bars from all the plots added. - // It would be wrong to just add the - // individual plots max y-value since that - // would in most cases give to large y-value. - $y=0; - if( $this->plots[0]->coords[0][$i] < 0 ) - $y=$this->plots[0]->coords[0][$i]; - for( $j = 1; $j < $this->nbrplots; $j++ ) { - if( $this->plots[$j]->coords[0][$i] < 0 ) - $y += $this->plots[ $j ]->coords[0][$i]; - } - $ymin[$i] = $y; - } - $ymin = Min($ysetmin,Min($ymin)); - // Bar always start at baseline - if( $ymin >= $this->ybase ) - $ymin = $this->ybase; - return array($xmin,$ymin); - } - - // Stroke acc bar plot - function Stroke($img,$xscale,$yscale) { - $pattern=NULL; - $img->SetLineWeight($this->weight); - $grad=null; - for($i=0; $i < $this->numpoints-1; $i++) { - $accy = 0; - $accy_neg = 0; - for($j=0; $j < $this->nbrplots; ++$j ) { - $img->SetColor($this->plots[$j]->color); - - if ( $this->plots[$j]->coords[0][$i] >= 0) { - $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); - $accyt=$yscale->Translate($accy); - $accy+=$this->plots[$j]->coords[0][$i]; - } - else { - //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) { - $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); - $accyt=$yscale->Translate($accy_neg); - $accy_neg+=$this->plots[$j]->coords[0][$i]; - } - - $xt=$xscale->Translate($i); - - if( $this->abswidth > -1 ) { - $abswidth=$this->abswidth; - } - else { - $abswidth=round($this->width*$xscale->scale_factor,0); - } - - $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); - - if( $this->bar_shadow ) { - $ssh = $this->bar_shadow_hsize; - $ssv = $this->bar_shadow_vsize; - - // We must also differ if we are a positive or negative bar. - if( $j === 0 ) { - // This gets extra complicated since we have to - // see all plots to see if we are negative. It could - // for example be that all plots are 0 until the very - // last one. We therefore need to save the initial setup - // for both the negative and positive case - - // In case the final bar is positive - $sp[0]=$pts[6]+1; $sp[1]=$pts[7]; - $sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv; - - // In case the final bar is negative - $nsp[0]=$pts[0]; $nsp[1]=$pts[1]; - $nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv; - $nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv; - $nsp[10]=$pts[6]+1; $nsp[11]=$pts[7]; - } - - if( $j === $this->nbrplots-1 ) { - // If this is the last plot of the bar and - // the total value is larger than 0 then we - // add the shadow. - if( is_array($this->bar_shadow_color) ) { - $numcolors = count($this->bar_shadow_color); - if( $numcolors == 0 ) { - JpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.'); - } - $img->PushColor($this->bar_shadow_color[$i % $numcolors]); - } - else { - $img->PushColor($this->bar_shadow_color); - } - - if( $accy > 0 ) { - $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv; - $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; - $sp[8]=$pts[2]; $sp[9]=$pts[3]-1; - $sp[10]=$pts[4]+1; $sp[11]=$pts[5]; - $img->FilledPolygon($sp,4); - } - elseif( $accy_neg < 0 ) { - $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv; - $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5]; - $img->FilledPolygon($nsp,4); - } - $img->PopColor(); - } - } - - - // If value is NULL or 0, then don't draw a bar at all - if ($this->plots[$j]->coords[0][$i] == 0 ) continue; - - if( $this->plots[$j]->grad ) { - if( $grad === null ) { - $grad = new Gradient($img); - } - if( is_array($this->plots[$j]->grad_fromcolor) ) { - // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array - // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be - // an array to specify both (from, to style) for each individual bar. The way to know the difference is - // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB - // triple. - $ng = count($this->plots[$j]->grad_fromcolor); - if( $ng === 3 ) { - if( is_numeric($this->plots[$j]->grad_fromcolor[0]) && $this->plots[$j]->grad_fromcolor[0] > 0 && - $this->plots[$j]->grad_fromcolor[0] < 256 ) { - // RGB Triple - $fromcolor = $this->plots[$j]->grad_fromcolor; - $tocolor = $this->plots[$j]->grad_tocolor; - $style = $this->plots[$j]->grad_style; - } - else { - $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0]; - $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1]; - $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2]; - } - } - else { - $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0]; - $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1]; - $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2]; - } - $grad->FilledRectangle($pts[2],$pts[3], - $pts[6],$pts[7], - $fromcolor,$tocolor,$style); - } - else { - $grad->FilledRectangle($pts[2],$pts[3], - $pts[6],$pts[7], - $this->plots[$j]->grad_fromcolor, - $this->plots[$j]->grad_tocolor, - $this->plots[$j]->grad_style); - } - } else { - if (is_array($this->plots[$j]->fill_color) ) { - $numcolors = count($this->plots[$j]->fill_color); - $fillcolor = $this->plots[$j]->fill_color[$i % $numcolors]; - // If the bar is specified to be non filled then the fill color is false - if( $fillcolor !== false ) { - $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]); - } - } - else { - $fillcolor = $this->plots[$j]->fill_color; - if( $fillcolor !== false ) { - $img->SetColor($this->plots[$j]->fill_color); - } - } - if( $fillcolor !== false ) { - $img->FilledPolygon($pts); - } - } - - $img->SetColor($this->plots[$j]->color); - - // Stroke the pattern - if( $this->plots[$j]->iPattern > -1 ) { - if( $pattern===NULL ) { - $pattern = new RectPatternFactory(); - } - - $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1); - $prect->SetDensity($this->plots[$j]->iPatternDensity); - if( $this->plots[$j]->coords[0][$i] < 0 ) { - $rx = $pts[0]; - $ry = $pts[1]; - } - else { - $rx = $pts[2]; - $ry = $pts[3]; - } - $width = abs($pts[4]-$pts[0])+1; - $height = abs($pts[1]-$pts[3])+1; - $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); - $prect->Stroke($img); - } - - - // CSIM array - - if( $i < count($this->plots[$j]->csimtargets) ) { - // Create the client side image map - $rpts = $img->ArrRotate($pts); - $csimcoord=round($rpts[0]).", ".round($rpts[1]); - for( $k=1; $k < 4; ++$k){ - $csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]); - } - if( ! empty($this->plots[$j]->csimtargets[$i]) ) { - $this->csimareas.= 'csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\" "; - - if( ! empty($this->plots[$j]->csimwintargets[$i]) ) { - $this->csimareas.= " target=\"".$this->plots[$j]->csimwintargets[$i]."\" "; - } - - $sval=''; - if( !empty($this->plots[$j]->csimalts[$i]) ) { - $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); - $this->csimareas .= " title=\"$sval\" "; - } - $this->csimareas .= " alt=\"$sval\" />\n"; - } - } - - $pts[] = $pts[0]; - $pts[] = $pts[1]; - $img->SetLineWeight($this->plots[$j]->weight); - $img->Polygon($pts); - $img->SetLineWeight(1); - } - - // Daw potential bar around the entire accbar bar - if( $this->weight > 0 ) { - $y=$yscale->Translate(0); - $img->SetColor($this->color); - $img->SetLineWeight($this->weight); - $img->Rectangle($pts[0],$y,$pts[6],$pts[5]); - } - - // Draw labels for each acc.bar - - $x=$pts[2]+($pts[4]-$pts[2])/2; - if($this->bar_shadow) $x += $ssh; - - // First stroke the accumulated value for the entire bar - // This value is always placed at the top/bottom of the bars - if( $accy_neg < 0 ) { - $y=$yscale->Translate($accy_neg); - $this->value->Stroke($img,$accy_neg,$x,$y); - } - else { - $y=$yscale->Translate($accy); - $this->value->Stroke($img,$accy,$x,$y); - } - - $accy = 0; - $accy_neg = 0; - for($j=0; $j < $this->nbrplots; ++$j ) { - - // We don't print 0 values in an accumulated bar plot - if( $this->plots[$j]->coords[0][$i] == 0 ) continue; - - if ($this->plots[$j]->coords[0][$i] > 0) { - $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); - $accyt=$yscale->Translate($accy); - if( $this->plots[$j]->valuepos=='center' ) { - $y = $accyt-($accyt-$yt)/2; - } - elseif( $this->plots[$j]->valuepos=='bottom' ) { - $y = $accyt; - } - else { // top or max - $y = $accyt-($accyt-$yt); - } - $accy+=$this->plots[$j]->coords[0][$i]; - if( $this->plots[$j]->valuepos=='center' ) { - $this->plots[$j]->value->SetAlign("center","center"); - $this->plots[$j]->value->SetMargin(0); - } - elseif( $this->plots[$j]->valuepos=='bottom' ) { - $this->plots[$j]->value->SetAlign('center','bottom'); - $this->plots[$j]->value->SetMargin(2); - } - else { - $this->plots[$j]->value->SetAlign('center','top'); - $this->plots[$j]->value->SetMargin(1); - } - } else { - $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); - $accyt=$yscale->Translate($accy_neg); - $accy_neg+=$this->plots[$j]->coords[0][$i]; - if( $this->plots[$j]->valuepos=='center' ) { - $y = $accyt-($accyt-$yt)/2; - } - elseif( $this->plots[$j]->valuepos=='bottom' ) { - $y = $accyt; - } - else { - $y = $accyt-($accyt-$yt); - } - if( $this->plots[$j]->valuepos=='center' ) { - $this->plots[$j]->value->SetAlign("center","center"); - $this->plots[$j]->value->SetMargin(0); - } - elseif( $this->plots[$j]->valuepos=='bottom' ) { - $this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top'); - $this->plots[$j]->value->SetMargin(-2); - } - else { - $this->plots[$j]->value->SetAlign('center','bottom'); - $this->plots[$j]->value->SetMargin(-1); - } - } - $this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],$x,$y); - } - - } - return true; - } -} // Class - -/* EOF */ -?> +numpoints; + } + + //--------------- + // PUBLIC METHODS + + // Set a drop shadow for the bar (or rather an "up-right" shadow) + function SetShadow($aColor="black",$aHSize=3,$aVSize=3,$aShow=true) { + $this->bar_shadow=$aShow; + $this->bar_shadow_color=$aColor; + $this->bar_shadow_vsize=$aVSize; + $this->bar_shadow_hsize=$aHSize; + + // Adjust the value margin to compensate for shadow + $this->value->margin += $aVSize; + } + + // DEPRECATED use SetYBase instead + function SetYMin($aYStartValue) { + //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead."); + $this->ybase=$aYStartValue; + } + + // Specify the base value for the bars + function SetYBase($aYStartValue) { + $this->ybase=$aYStartValue; + } + + // The method will take the specified pattern anre + // return a pattern index that corresponds to the original + // patterm being rotated 90 degreees. This is needed when plottin + // Horizontal bars + function RotatePattern($aPat,$aRotate=true) { + $rotate = array(1 => 2, 2 => 1, 3 => 3, 4 => 5, 5 => 4, 6 => 6, 7 => 7, 8 => 8); + if( $aRotate ) { + return $rotate[$aPat]; + } + else { + return $aPat; + } + } + + function Legend($graph) { + if( $this->grad && $this->legend!="" && !$this->fill ) { + $color=array($this->grad_fromcolor,$this->grad_tocolor); + // In order to differentiate between gradients and cooors specified as an RGB triple + $graph->legend->Add($this->legend,$color,"",-$this->grad_style, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + elseif( $this->legend!="" && ($this->iPattern > -1 || is_array($this->iPattern)) ) { + if( is_array($this->iPattern) ) { + $p1 = $this->RotatePattern( $this->iPattern[0], $graph->img->a == 90 ); + $p2 = $this->iPatternColor[0]; + $p3 = $this->iPatternDensity[0]; + } + else { + $p1 = $this->RotatePattern( $this->iPattern, $graph->img->a == 90 ); + $p2 = $this->iPatternColor; + $p3 = $this->iPatternDensity; + } + if( $p3 < 90 ) $p3 += 5; + $color = array($p1,$p2,$p3,$this->fill_color); + // A kludge: Too mark that we add a pattern we use a type value of < 100 + $graph->legend->Add($this->legend,$color,"",-101, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + elseif( $this->fill_color && $this->legend!="" ) { + if( is_array($this->fill_color) ) { + $graph->legend->Add($this->legend,$this->fill_color[0],"",0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + else { + $graph->legend->Add($this->legend,$this->fill_color,"",0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + parent::PreStrokeAdjust($graph); + + // If we are using a log Y-scale we want the base to be at the + // minimum Y-value unless the user have specifically set some other + // value than the default. + if( substr($graph->axtype,-3,3)=="log" && $this->ybase==0 ) + $this->ybase = $graph->yaxis->scale->GetMinVal(); + + // For a "text" X-axis scale we will adjust the + // display of the bars a little bit. + if( substr($graph->axtype,0,3)=="tex" ) { + // Position the ticks between the bars + $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); + + // Center the bars + if( $this->abswidth > -1 ) { + $graph->SetTextScaleAbsCenterOff($this->abswidth); + } + else { + if( $this->align == "center" ) + $graph->SetTextScaleOff(0.5-$this->width/2); + elseif( $this->align == "right" ) + $graph->SetTextScaleOff(1-$this->width); + } + } + elseif( ($this instanceof AccBarPlot) || ($this instanceof GroupBarPlot) ) { + // We only set an absolute width for linear and int scale + // for text scale the width will be set to a fraction of + // the majstep width. + if( $this->abswidth == -1 ) { + // Not set + // set width to a visuable sensible default + $this->abswidth = $graph->img->plotwidth/(2*$this->numpoints); + } + } + } + + function Min() { + $m = parent::Min(); + if( $m[1] >= $this->ybase ) $m[1] = $this->ybase; + return $m; + } + + function Max() { + $m = parent::Max(); + if( $m[1] <= $this->ybase ) $m[1] = $this->ybase; + return $m; + } + + // Specify width as fractions of the major stepo size + function SetWidth($aWidth) { + if( $aWidth > 1 ) { + // Interpret this as absolute width + $this->abswidth=$aWidth; + } + else { + $this->width=$aWidth; + } + } + + // Specify width in absolute pixels. If specified this + // overrides SetWidth() + function SetAbsWidth($aWidth) { + $this->abswidth=$aWidth; + } + + function SetAlign($aAlign) { + $this->align=$aAlign; + } + + function SetNoFill() { + $this->grad = false; + $this->fill_color=false; + $this->fill=false; + } + + function SetFillColor($aColor) { + // Do an extra error check if the color is specified as an RGB array triple + // In that case convert it to a hex string since it will otherwise be + // interpretated as an array of colors for each individual bar. + + $aColor = RGB::tryHexConversion($aColor); + $this->fill = true ; + $this->fill_color=$aColor; + + } + + function SetFillGradient($aFromColor,$aToColor=null,$aStyle=null) { + $this->grad = true; + $this->grad_fromcolor = $aFromColor; + $this->grad_tocolor = $aToColor; + $this->grad_style = $aStyle; + } + + function SetValuePos($aPos) { + $this->valuepos = $aPos; + } + + function SetPattern($aPattern, $aColor='black'){ + if( is_array($aPattern) ) { + $n = count($aPattern); + $this->iPattern = array(); + $this->iPatternDensity = array(); + if( is_array($aColor) ) { + $this->iPatternColor = array(); + if( count($aColor) != $n ) { + JpGraphError::RaiseL(2001);//('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()'); + } + } + else { + $this->iPatternColor = $aColor; + } + for( $i=0; $i < $n; ++$i ) { + $this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]); + if( is_array($aColor) ) { + $this->iPatternColor[$i] = $aColor[$i]; + } + } + } + else { + $this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity); + $this->iPatternColor = $aColor; + } + } + + function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){ + switch( $aPattern ) { + case PATTERN_DIAG1: + $aPatternValue= 1; + $aDensity = 92; + break; + case PATTERN_DIAG2: + $aPatternValue= 1; + $aDensity = 78; + break; + case PATTERN_DIAG3: + $aPatternValue= 2; + $aDensity = 92; + break; + case PATTERN_DIAG4: + $aPatternValue= 2; + $aDensity = 78; + break; + case PATTERN_CROSS1: + $aPatternValue= 8; + $aDensity = 90; + break; + case PATTERN_CROSS2: + $aPatternValue= 8; + $aDensity = 78; + break; + case PATTERN_CROSS3: + $aPatternValue= 8; + $aDensity = 65; + break; + case PATTERN_CROSS4: + $aPatternValue= 7; + $aDensity = 90; + break; + case PATTERN_STRIPE1: + $aPatternValue= 5; + $aDensity = 94; + break; + case PATTERN_STRIPE2: + $aPatternValue= 5; + $aDensity = 85; + break; + default: + JpGraphError::RaiseL(2002); + //('Unknown pattern specified in call to BarPlot::SetPattern()'); + } + } + + function Stroke($img,$xscale,$yscale) { + + $numpoints = count($this->coords[0]); + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) { + JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); + //"Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints"); + } + else { + $exist_x = true; + } + } + else { + $exist_x = false; + } + + + $numbars=count($this->coords[0]); + + // Use GetMinVal() instead of scale[0] directly since in the case + // of log scale we get a correct value. Log scales will have negative + // values for values < 1 while still not representing negative numbers. + if( $yscale->GetMinVal() >= 0 ) + $zp=$yscale->scale_abs[0]; + else { + $zp=$yscale->Translate(0); + } + + if( $this->abswidth > -1 ) { + $abswidth=$this->abswidth; + } + else { + $abswidth=round($this->width*$xscale->scale_factor,0); + } + + // Count pontetial pattern array to avoid doing the count for each iteration + if( is_array($this->iPattern) ) { + $np = count($this->iPattern); + } + + $grad = null; + for($i=0; $i < $numbars; ++$i) { + + // If value is NULL, or 0 then don't draw a bar at all + if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' ) + continue; + + if( $exist_x ) { + $x=$this->coords[1][$i]; + } + else { + $x=$i; + } + + $x=$xscale->Translate($x); + + // Comment Note: This confuses the positioning when using acc together with + // grouped bars. Workaround for fixing #191 + /* + if( !$xscale->textscale ) { + if($this->align=="center") + $x -= $abswidth/2; + elseif($this->align=="right") + $x -= $abswidth; + } + */ + // Stroke fill color and fill gradient + $pts=array( + $x,$zp, + $x,$yscale->Translate($this->coords[0][$i]), + $x+$abswidth,$yscale->Translate($this->coords[0][$i]), + $x+$abswidth,$zp); + if( $this->grad ) { + if( $grad === null ) { + $grad = new Gradient($img); + } + if( is_array($this->grad_fromcolor) ) { + // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array + // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be + // an array to specify both (from, to style) for each individual bar. The way to know the difference is + // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB + // triple. + $ng = count($this->grad_fromcolor); + if( $ng === 3 ) { + if( is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256 ) { + // RGB Triple + $fromcolor = $this->grad_fromcolor; + $tocolor = $this->grad_tocolor; + $style = $this->grad_style; + } + else { + $fromcolor = $this->grad_fromcolor[$i % $ng][0]; + $tocolor = $this->grad_fromcolor[$i % $ng][1]; + $style = $this->grad_fromcolor[$i % $ng][2]; + } + } + else { + $fromcolor = $this->grad_fromcolor[$i % $ng][0]; + $tocolor = $this->grad_fromcolor[$i % $ng][1]; + $style = $this->grad_fromcolor[$i % $ng][2]; + } + $grad->FilledRectangle($pts[2],$pts[3], + $pts[6],$pts[7], + $fromcolor,$tocolor,$style); + } + else { + $grad->FilledRectangle($pts[2],$pts[3], + $pts[6],$pts[7], + $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); + } + } + elseif( !empty($this->fill_color) ) { + if(is_array($this->fill_color)) { + $img->PushColor($this->fill_color[$i % count($this->fill_color)]); + } else { + $img->PushColor($this->fill_color); + } + $img->FilledPolygon($pts); + $img->PopColor(); + } + + + // Remember value of this bar + $val=$this->coords[0][$i]; + + if( !empty($val) && !is_numeric($val) ) { + JpGraphError::RaiseL(2004,$i,$val); + //'All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\''); + } + + // Determine the shadow + if( $this->bar_shadow && $val != 0) { + + $ssh = $this->bar_shadow_hsize; + $ssv = $this->bar_shadow_vsize; + // Create points to create a "upper-right" shadow + if( $val > 0 ) { + $sp[0]=$pts[6]; $sp[1]=$pts[7]; + $sp[2]=$pts[4]; $sp[3]=$pts[5]; + $sp[4]=$pts[2]; $sp[5]=$pts[3]; + $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; + $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; + $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; + } + elseif( $val < 0 ) { + $sp[0]=$pts[4]; $sp[1]=$pts[5]; + $sp[2]=$pts[6]; $sp[3]=$pts[7]; + $sp[4]=$pts[0]; $sp[5]=$pts[1]; + $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; + $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; + $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; + } + if( is_array($this->bar_shadow_color) ) { + $numcolors = count($this->bar_shadow_color); + if( $numcolors == 0 ) { + JpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.'); + } + $img->PushColor($this->bar_shadow_color[$i % $numcolors]); + } + else { + $img->PushColor($this->bar_shadow_color); + } + $img->FilledPolygon($sp); + $img->PopColor(); + } + + // Stroke the pattern + if( is_array($this->iPattern) ) { + $f = new RectPatternFactory(); + if( is_array($this->iPatternColor) ) { + $pcolor = $this->iPatternColor[$i % $np]; + } + else { + $pcolor = $this->iPatternColor; + } + $prect = $f->Create($this->iPattern[$i % $np],$pcolor,1); + $prect->SetDensity($this->iPatternDensity[$i % $np]); + + if( $val < 0 ) { + $rx = $pts[0]; + $ry = $pts[1]; + } + else { + $rx = $pts[2]; + $ry = $pts[3]; + } + $width = abs($pts[4]-$pts[0])+1; + $height = abs($pts[1]-$pts[3])+1; + $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); + $prect->Stroke($img); + } + else { + if( $this->iPattern > -1 ) { + $f = new RectPatternFactory(); + $prect = $f->Create($this->iPattern,$this->iPatternColor,1); + $prect->SetDensity($this->iPatternDensity); + if( $val < 0 ) { + $rx = $pts[0]; + $ry = $pts[1]; + } + else { + $rx = $pts[2]; + $ry = $pts[3]; + } + $width = abs($pts[4]-$pts[0])+1; + $height = abs($pts[1]-$pts[3])+1; + $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); + $prect->Stroke($img); + } + } + + // Stroke the outline of the bar + if( is_array($this->color) ) { + $img->SetColor($this->color[$i % count($this->color)]); + } + else { + $img->SetColor($this->color); + } + + $pts[] = $pts[0]; + $pts[] = $pts[1]; + + if( $this->weight > 0 ) { + $img->SetLineWeight($this->weight); + $img->Polygon($pts); + } + + // Determine how to best position the values of the individual bars + $x=$pts[2]+($pts[4]-$pts[2])/2; + $this->value->SetMargin(5); + + if( $this->valuepos=='top' ) { + $y=$pts[3]; + if( $img->a === 90 ) { + if( $val < 0 ) { + $this->value->SetAlign('right','center'); + } + else { + $this->value->SetAlign('left','center'); + } + + } + else { + if( $val < 0 ) { + $this->value->SetMargin(-5); + $y=$pts[1]; + $this->value->SetAlign('center','bottom'); + } + else { + $this->value->SetAlign('center','bottom'); + } + + } + $this->value->Stroke($img,$val,$x,$y); + } + elseif( $this->valuepos=='max' ) { + $y=$pts[3]; + if( $img->a === 90 ) { + if( $val < 0 ) + $this->value->SetAlign('left','center'); + else + $this->value->SetAlign('right','center'); + } + else { + if( $val < 0 ) { + $this->value->SetAlign('center','bottom'); + } + else { + $this->value->SetAlign('center','top'); + } + } + $this->value->SetMargin(-5); + $this->value->Stroke($img,$val,$x,$y); + } + elseif( $this->valuepos=='center' ) { + $y = ($pts[3] + $pts[1])/2; + $this->value->SetAlign('center','center'); + $this->value->SetMargin(0); + $this->value->Stroke($img,$val,$x,$y); + } + elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) { + $y=$pts[1]; + if( $img->a === 90 ) { + if( $val < 0 ) + $this->value->SetAlign('right','center'); + else + $this->value->SetAlign('left','center'); + } + $this->value->SetMargin(3); + $this->value->Stroke($img,$val,$x,$y); + } + else { + JpGraphError::RaiseL(2006,$this->valuepos); + //'Unknown position for values on bars :'.$this->valuepos); + } + // Create the client side image map + $rpts = $img->ArrRotate($pts); + $csimcoord=round($rpts[0]).", ".round($rpts[1]); + for( $j=1; $j < 4; ++$j){ + $csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]); + } + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= 'csimareas .= " href=\"".htmlentities($this->csimtargets[$i])."\""; + + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + + $sval=''; + if( !empty($this->csimalts[$i]) ) { + $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); + $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; + } + $this->csimareas .= " />\n"; + } + } + return true; + } +} // Class + +//=================================================== +// CLASS GroupBarPlot +// Description: Produce grouped bar plots +//=================================================== +class GroupBarPlot extends BarPlot { + private $plots, $nbrplots=0; + //--------------- + // CONSTRUCTOR + function GroupBarPlot($plots) { + $this->width=0.7; + $this->plots = $plots; + $this->nbrplots = count($plots); + if( $this->nbrplots < 1 ) { + JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.'); + } + for($i=0; $i < $this->nbrplots; ++$i ) { + if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { + JpGraphError::RaiseL(2008,$i);//("Group bar plot element nbr $i is undefined or empty."); + } + } + $this->numpoints = $plots[0]->numpoints; + $this->width=0.7; + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + $c = get_class($this->plots[$i]); + if( !($this->plots[$i] instanceof BarPlot) ) { + JpGraphError::RaiseL(2009,$c); + //('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')'); + } + $this->plots[$i]->DoLegend($graph); + } + } + + function Min() { + list($xmin,$ymin) = $this->plots[0]->Min(); + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + list($xm,$ym) = $this->plots[$i]->Min(); + $xmin = max($xmin,$xm); + $ymin = min($ymin,$ym); + } + return array($xmin,$ymin); + } + + function Max() { + list($xmax,$ymax) = $this->plots[0]->Max(); + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + list($xm,$ym) = $this->plots[$i]->Max(); + $xmax = max($xmax,$xm); + $ymax = max($ymax,$ym); + } + return array($xmax,$ymax); + } + + function GetCSIMareas() { + $n = count($this->plots); + $csimareas=''; + for($i=0; $i < $n; ++$i) { + $csimareas .= $this->plots[$i]->csimareas; + } + return $csimareas; + } + + // Stroke all the bars next to each other + function Stroke($img,$xscale,$yscale) { + $tmp=$xscale->off; + $n = count($this->plots); + $subwidth = $this->width/$this->nbrplots ; + + for( $i=0; $i < $n; ++$i ) { + $this->plots[$i]->ymin=$this->ybase; + $this->plots[$i]->SetWidth($subwidth); + + // If the client have used SetTextTickInterval() then + // major_step will be > 1 and the positioning will fail. + // If we assume it is always one the positioning will work + // fine with a text scale but this will not work with + // arbitrary linear scale + $xscale->off = $tmp+$i*round($xscale->scale_factor* $subwidth); + $this->plots[$i]->Stroke($img,$xscale,$yscale); + } + $xscale->off=$tmp; + } +} // Class + +//=================================================== +// CLASS AccBarPlot +// Description: Produce accumulated bar plots +//=================================================== +class AccBarPlot extends BarPlot { + private $plots=null,$nbrplots=0; + //--------------- + // CONSTRUCTOR + function __construct($plots) { + $this->plots = $plots; + $this->nbrplots = count($plots); + if( $this->nbrplots < 1 ) { + JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.'); + } + for($i=0; $i < $this->nbrplots; ++$i ) { + if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { + JpGraphError::RaiseL(2011,$i);//("Acc bar plot element nbr $i is undefined or empty."); + } + } + + // We can only allow individual plost which do not have specified X-positions + for($i=0; $i < $this->nbrplots; ++$i ) { + if( !empty($this->plots[$i]->coords[1]) ) { + JpGraphError::RaiseL(2015); + //'Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-positions.'); + } + } + + // Use 0 weight by default which means that the individual bar + // weights will be used per part n the accumulated bar + $this->SetWeight(0); + + $this->numpoints = $plots[0]->numpoints; + $this->value = new DisplayValue(); + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + $n = count($this->plots); + for( $i=$n-1; $i >= 0; --$i ) { + $c = get_class($this->plots[$i]); + if( !($this->plots[$i] instanceof BarPlot) ) { + JpGraphError::RaiseL(2012,$c); + //('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')'); + } + $this->plots[$i]->DoLegend($graph); + } + } + + function Max() { + list($xmax) = $this->plots[0]->Max(); + $nmax=0; + for($i=0; $i < count($this->plots); ++$i) { + $n = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$n); + list($x) = $this->plots[$i]->Max(); + $xmax = max($xmax,$x); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for bar $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots max y-value since that + // would in most cases give to large y-value. + $y=0; + if( !isset($this->plots[0]->coords[0][$i]) ) { + JpGraphError::RaiseL(2014); + } + if( $this->plots[0]->coords[0][$i] > 0 ) + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + if( !isset($this->plots[$j]->coords[0][$i]) ) { + JpGraphError::RaiseL(2014); + } + if( $this->plots[$j]->coords[0][$i] > 0 ) + $y += $this->plots[$j]->coords[0][$i]; + } + $ymax[$i] = $y; + } + $ymax = max($ymax); + + // Bar always start at baseline + if( $ymax <= $this->ybase ) + $ymax = $this->ybase; + return array($xmax,$ymax); + } + + function Min() { + $nmax=0; + list($xmin,$ysetmin) = $this->plots[0]->Min(); + for($i=0; $i < count($this->plots); ++$i) { + $n = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$n); + list($x,$y) = $this->plots[$i]->Min(); + $xmin = Min($xmin,$x); + $ysetmin = Min($y,$ysetmin); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for bar $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots max y-value since that + // would in most cases give to large y-value. + $y=0; + if( $this->plots[0]->coords[0][$i] < 0 ) + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + if( $this->plots[$j]->coords[0][$i] < 0 ) + $y += $this->plots[ $j ]->coords[0][$i]; + } + $ymin[$i] = $y; + } + $ymin = Min($ysetmin,Min($ymin)); + // Bar always start at baseline + if( $ymin >= $this->ybase ) + $ymin = $this->ybase; + return array($xmin,$ymin); + } + + // Stroke acc bar plot + function Stroke($img,$xscale,$yscale) { + $pattern=NULL; + $img->SetLineWeight($this->weight); + $grad=null; + for($i=0; $i < $this->numpoints-1; $i++) { + $accy = 0; + $accy_neg = 0; + for($j=0; $j < $this->nbrplots; ++$j ) { + $img->SetColor($this->plots[$j]->color); + + if ( $this->plots[$j]->coords[0][$i] >= 0) { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); + $accyt=$yscale->Translate($accy); + $accy+=$this->plots[$j]->coords[0][$i]; + } + else { + //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); + $accyt=$yscale->Translate($accy_neg); + $accy_neg+=$this->plots[$j]->coords[0][$i]; + } + + $xt=$xscale->Translate($i); + + if( $this->abswidth > -1 ) { + $abswidth=$this->abswidth; + } + else { + $abswidth=round($this->width*$xscale->scale_factor,0); + } + + $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); + + if( $this->bar_shadow ) { + $ssh = $this->bar_shadow_hsize; + $ssv = $this->bar_shadow_vsize; + + // We must also differ if we are a positive or negative bar. + if( $j === 0 ) { + // This gets extra complicated since we have to + // see all plots to see if we are negative. It could + // for example be that all plots are 0 until the very + // last one. We therefore need to save the initial setup + // for both the negative and positive case + + // In case the final bar is positive + $sp[0]=$pts[6]+1; $sp[1]=$pts[7]; + $sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv; + + // In case the final bar is negative + $nsp[0]=$pts[0]; $nsp[1]=$pts[1]; + $nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv; + $nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv; + $nsp[10]=$pts[6]+1; $nsp[11]=$pts[7]; + } + + if( $j === $this->nbrplots-1 ) { + // If this is the last plot of the bar and + // the total value is larger than 0 then we + // add the shadow. + if( is_array($this->bar_shadow_color) ) { + $numcolors = count($this->bar_shadow_color); + if( $numcolors == 0 ) { + JpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.'); + } + $img->PushColor($this->bar_shadow_color[$i % $numcolors]); + } + else { + $img->PushColor($this->bar_shadow_color); + } + + if( $accy > 0 ) { + $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv; + $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; + $sp[8]=$pts[2]; $sp[9]=$pts[3]-1; + $sp[10]=$pts[4]+1; $sp[11]=$pts[5]; + $img->FilledPolygon($sp,4); + } + elseif( $accy_neg < 0 ) { + $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv; + $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5]; + $img->FilledPolygon($nsp,4); + } + $img->PopColor(); + } + } + + + // If value is NULL or 0, then don't draw a bar at all + if ($this->plots[$j]->coords[0][$i] == 0 ) continue; + + if( $this->plots[$j]->grad ) { + if( $grad === null ) { + $grad = new Gradient($img); + } + if( is_array($this->plots[$j]->grad_fromcolor) ) { + // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array + // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be + // an array to specify both (from, to style) for each individual bar. The way to know the difference is + // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB + // triple. + $ng = count($this->plots[$j]->grad_fromcolor); + if( $ng === 3 ) { + if( is_numeric($this->plots[$j]->grad_fromcolor[0]) && $this->plots[$j]->grad_fromcolor[0] > 0 && + $this->plots[$j]->grad_fromcolor[0] < 256 ) { + // RGB Triple + $fromcolor = $this->plots[$j]->grad_fromcolor; + $tocolor = $this->plots[$j]->grad_tocolor; + $style = $this->plots[$j]->grad_style; + } + else { + $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0]; + $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1]; + $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2]; + } + } + else { + $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0]; + $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1]; + $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2]; + } + $grad->FilledRectangle($pts[2],$pts[3], + $pts[6],$pts[7], + $fromcolor,$tocolor,$style); + } + else { + $grad->FilledRectangle($pts[2],$pts[3], + $pts[6],$pts[7], + $this->plots[$j]->grad_fromcolor, + $this->plots[$j]->grad_tocolor, + $this->plots[$j]->grad_style); + } + } else { + if (is_array($this->plots[$j]->fill_color) ) { + $numcolors = count($this->plots[$j]->fill_color); + $fillcolor = $this->plots[$j]->fill_color[$i % $numcolors]; + // If the bar is specified to be non filled then the fill color is false + if( $fillcolor !== false ) { + $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]); + } + } + else { + $fillcolor = $this->plots[$j]->fill_color; + if( $fillcolor !== false ) { + $img->SetColor($this->plots[$j]->fill_color); + } + } + if( $fillcolor !== false ) { + $img->FilledPolygon($pts); + } + } + + $img->SetColor($this->plots[$j]->color); + + // Stroke the pattern + if( $this->plots[$j]->iPattern > -1 ) { + if( $pattern===NULL ) { + $pattern = new RectPatternFactory(); + } + + $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1); + $prect->SetDensity($this->plots[$j]->iPatternDensity); + if( $this->plots[$j]->coords[0][$i] < 0 ) { + $rx = $pts[0]; + $ry = $pts[1]; + } + else { + $rx = $pts[2]; + $ry = $pts[3]; + } + $width = abs($pts[4]-$pts[0])+1; + $height = abs($pts[1]-$pts[3])+1; + $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); + $prect->Stroke($img); + } + + + // CSIM array + + if( $i < count($this->plots[$j]->csimtargets) ) { + // Create the client side image map + $rpts = $img->ArrRotate($pts); + $csimcoord=round($rpts[0]).", ".round($rpts[1]); + for( $k=1; $k < 4; ++$k){ + $csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]); + } + if( ! empty($this->plots[$j]->csimtargets[$i]) ) { + $this->csimareas.= 'csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\" "; + + if( ! empty($this->plots[$j]->csimwintargets[$i]) ) { + $this->csimareas.= " target=\"".$this->plots[$j]->csimwintargets[$i]."\" "; + } + + $sval=''; + if( !empty($this->plots[$j]->csimalts[$i]) ) { + $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); + $this->csimareas .= " title=\"$sval\" "; + } + $this->csimareas .= " alt=\"$sval\" />\n"; + } + } + + $pts[] = $pts[0]; + $pts[] = $pts[1]; + $img->SetLineWeight($this->plots[$j]->weight); + $img->Polygon($pts); + $img->SetLineWeight(1); + } + + // Daw potential bar around the entire accbar bar + if( $this->weight > 0 ) { + $y=$yscale->Translate(0); + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $img->Rectangle($pts[0],$y,$pts[6],$pts[5]); + } + + // Draw labels for each acc.bar + + $x=$pts[2]+($pts[4]-$pts[2])/2; + if($this->bar_shadow) $x += $ssh; + + // First stroke the accumulated value for the entire bar + // This value is always placed at the top/bottom of the bars + if( $accy_neg < 0 ) { + $y=$yscale->Translate($accy_neg); + $this->value->Stroke($img,$accy_neg,$x,$y); + } + else { + $y=$yscale->Translate($accy); + $this->value->Stroke($img,$accy,$x,$y); + } + + $accy = 0; + $accy_neg = 0; + for($j=0; $j < $this->nbrplots; ++$j ) { + + // We don't print 0 values in an accumulated bar plot + if( $this->plots[$j]->coords[0][$i] == 0 ) continue; + + if ($this->plots[$j]->coords[0][$i] > 0) { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); + $accyt=$yscale->Translate($accy); + if( $this->plots[$j]->valuepos=='center' ) { + $y = $accyt-($accyt-$yt)/2; + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $y = $accyt; + } + else { // top or max + $y = $accyt-($accyt-$yt); + } + $accy+=$this->plots[$j]->coords[0][$i]; + if( $this->plots[$j]->valuepos=='center' ) { + $this->plots[$j]->value->SetAlign("center","center"); + $this->plots[$j]->value->SetMargin(0); + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $this->plots[$j]->value->SetAlign('center','bottom'); + $this->plots[$j]->value->SetMargin(2); + } + else { + $this->plots[$j]->value->SetAlign('center','top'); + $this->plots[$j]->value->SetMargin(1); + } + } else { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); + $accyt=$yscale->Translate($accy_neg); + $accy_neg+=$this->plots[$j]->coords[0][$i]; + if( $this->plots[$j]->valuepos=='center' ) { + $y = $accyt-($accyt-$yt)/2; + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $y = $accyt; + } + else { + $y = $accyt-($accyt-$yt); + } + if( $this->plots[$j]->valuepos=='center' ) { + $this->plots[$j]->value->SetAlign("center","center"); + $this->plots[$j]->value->SetMargin(0); + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top'); + $this->plots[$j]->value->SetMargin(-2); + } + else { + $this->plots[$j]->value->SetAlign('center','bottom'); + $this->plots[$j]->value->SetMargin(-1); + } + } + $this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],$x,$y); + } + + } + return true; + } +} // Class + +/* EOF */ +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_canvas.php b/ext/jpgraph-3.0.7/src/jpgraph_canvas.php index 4e9f964..6f4f203 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_canvas.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_canvas.php @@ -1,95 +1,95 @@ -StrokePlotArea(); - } - - // Method description - function Stroke($aStrokeFileName="") { - if( $this->texts != null ) { - for($i=0; $i < count($this->texts); ++$i) { - $this->texts[$i]->Stroke($this->img); - } - } - if( $this->iTables !== null ) { - for($i=0; $i < count($this->iTables); ++$i) { - $this->iTables[$i]->Stroke($this->img); - } - } - $this->StrokeTitles(); - - // If the filename is the predefined value = '_csim_special_' - // we assume that the call to stroke only needs to do enough - // to correctly generate the CSIM maps. - // We use this variable to skip things we don't strictly need - // to do to generate the image map to improve performance - // a best we can. Therefor you will see a lot of tests !$_csim in the - // code below. - $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); - - // We need to know if we have stroked the plot in the - // GetCSIMareas. Otherwise the CSIM hasn't been generated - // and in the case of GetCSIM called before stroke to generate - // CSIM without storing an image to disk GetCSIM must call Stroke. - $this->iHasStroked = true; - - if( !$_csim ) { - - // Should we do any final image transformation - if( $this->iImgTrans ) { - if( !class_exists('ImgTrans',false) ) { - require_once('jpgraph_imgtrans.php'); - } - - $tform = new ImgTrans($this->img->img); - $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, - $this->iImgTransDirection,$this->iImgTransHighQ, - $this->iImgTransMinSize,$this->iImgTransFillColor, - $this->iImgTransBorder); - } - - - // If the filename is given as the special _IMG_HANDLER - // then the image handler is returned and the image is NOT - // streamed back - if( $aStrokeFileName == _IMG_HANDLER ) { - return $this->img->img; - } - else { - // Finally stream the generated picture - $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); - return true; - } - } - } -} // Class - -/* EOF */ +StrokePlotArea(); + } + + // Method description + function Stroke($aStrokeFileName="") { + if( $this->texts != null ) { + for($i=0; $i < count($this->texts); ++$i) { + $this->texts[$i]->Stroke($this->img); + } + } + if( $this->iTables !== null ) { + for($i=0; $i < count($this->iTables); ++$i) { + $this->iTables[$i]->Stroke($this->img); + } + } + $this->StrokeTitles(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + if( !$_csim ) { + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special _IMG_HANDLER + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + return true; + } + } + } +} // Class + +/* EOF */ ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_canvtools.php b/ext/jpgraph-3.0.7/src/jpgraph_canvtools.php index b0ed4a9..f52381f 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_canvtools.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_canvtools.php @@ -1,523 +1,523 @@ -g = $graph; - $this->w = $graph->img->width; - $this->h = $graph->img->height; - $this->ixmin = $xmin; - $this->ixmax = $xmax; - $this->iymin = $ymin; - $this->iymax = $ymax; - } - - function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) { - $this->ixmin = $xmin; - $this->ixmax = $xmax; - $this->iymin = $ymin; - $this->iymax = $ymax; - } - - function Get() { - return array($this->ixmin,$this->ixmax,$this->iymin,$this->iymax); - } - - function Translate($x,$y) { - $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); - $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); - return array($xp,$yp); - } - - function TranslateX($x) { - $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); - return $xp; - } - - function TranslateY($y) { - $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); - return $yp; - } - -} - - -//=================================================== -// CLASS Shape -// Description: Methods to draw shapes on canvas -//=================================================== -class Shape { - private $img,$scale; - - function __construct($aGraph,$scale) { - $this->img = $aGraph->img; - $this->img->SetColor('black'); - $this->scale = $scale; - } - - function SetColor($aColor) { - $this->img->SetColor($aColor); - } - - function Line($x1,$y1,$x2,$y2) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - list($x2,$y2) = $this->scale->Translate($x2,$y2); - $this->img->Line($x1,$y1,$x2,$y2); - } - - function SetLineWeight($aWeight) { - $this->img->SetLineWeight($aWeight); - } - - function Polygon($p,$aClosed=false) { - $n=count($p); - for($i=0; $i < $n; $i+=2 ) { - $p[$i] = $this->scale->TranslateX($p[$i]); - $p[$i+1] = $this->scale->TranslateY($p[$i+1]); - } - $this->img->Polygon($p,$aClosed); - } - - function FilledPolygon($p) { - $n=count($p); - for($i=0; $i < $n; $i+=2 ) { - $p[$i] = $this->scale->TranslateX($p[$i]); - $p[$i+1] = $this->scale->TranslateY($p[$i+1]); - } - $this->img->FilledPolygon($p); - } - - - // Draw a bezier curve with defining points in the $aPnts array - // using $aSteps steps. - // 0=x0, 1=y0 - // 2=x1, 3=y1 - // 4=x2, 5=y2 - // 6=x3, 7=y3 - function Bezier($p,$aSteps=40) { - $x0 = $p[0]; - $y0 = $p[1]; - // Calculate coefficients - $cx = 3*($p[2]-$p[0]); - $bx = 3*($p[4]-$p[2])-$cx; - $ax = $p[6]-$p[0]-$cx-$bx; - $cy = 3*($p[3]-$p[1]); - $by = 3*($p[5]-$p[3])-$cy; - $ay = $p[7]-$p[1]-$cy-$by; - - // Step size - $delta = 1.0/$aSteps; - - $x_old = $x0; - $y_old = $y0; - for($t=$delta; $t<=1.0; $t+=$delta) { - $tt = $t*$t; $ttt=$tt*$t; - $x = $ax*$ttt + $bx*$tt + $cx*$t + $x0; - $y = $ay*$ttt + $by*$tt + $cy*$t + $y0; - $this->Line($x_old,$y_old,$x,$y); - $x_old = $x; - $y_old = $y; - } - $this->Line($x_old,$y_old,$p[6],$p[7]); - } - - function Rectangle($x1,$y1,$x2,$y2) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - list($x2,$y2) = $this->scale->Translate($x2,$y2); - $this->img->Rectangle($x1,$y1,$x2,$y2); - } - - function FilledRectangle($x1,$y1,$x2,$y2) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - list($x2,$y2) = $this->scale->Translate($x2,$y2); - $this->img->FilledRectangle($x1,$y1,$x2,$y2); - } - - function Circle($x1,$y1,$r) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - if( $r >= 0 ) - $r = $this->scale->TranslateX($r); - else - $r = -$r; - $this->img->Circle($x1,$y1,$r); - } - - function FilledCircle($x1,$y1,$r) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - if( $r >= 0 ) - $r = $this->scale->TranslateX($r); - else - $r = -$r; - $this->img->FilledCircle($x1,$y1,$r); - } - - function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - list($x2,$y2) = $this->scale->Translate($x2,$y2); - - if( $r == null ) - $r = 5; - elseif( $r >= 0 ) - $r = $this->scale->TranslateX($r); - else - $r = -$r; - $this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r); - } - - function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - list($x2,$y2) = $this->scale->Translate($x2,$y2); - - if( $r == null ) - $r = 5; - elseif( $r > 0 ) - $r = $this->scale->TranslateX($r); - else - $r = -$r; - $this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r); - } - - function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - list($x2,$y2) = $this->scale->Translate($x2,$y2); - if( $shadow_width == null ) - $shadow_width=4; - else - $shadow_width=$this->scale->TranslateX($shadow_width); - $this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color); - } - - function SetTextAlign($halign,$valign="bottom") { - $this->img->SetTextAlign($halign,$valign="bottom"); - } - - function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align="left") { - list($x1,$y1) = $this->scale->Translate($x1,$y1); - $this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align); - } - - // A rounded rectangle where one of the corner has been moved "into" the - // rectangle 'iw' width and 'ih' height. Corners: - // 0=Top left, 1=top right, 2=bottom right, 3=bottom left - function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor="",$r=4) { - - list($xt,$yt) = $this->scale->Translate($xt,$yt); - list($w,$h) = $this->scale->Translate($w,$h); - list($iw,$ih) = $this->scale->Translate($iw,$ih); - - $xr = $xt + $w - 0; - $yl = $yt + $h - 0; - - switch( $aCorner ) { - case 0: // Upper left - - // Bottom line, left & right arc - $this->img->Line($xt+$r,$yl,$xr-$r,$yl); - $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); - $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); - - // Right line, Top right arc - $this->img->Line($xr,$yt+$r,$xr,$yl-$r); - $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); - - // Top line, Top left arc - $this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt); - $this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270); - - // Left line - $this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r); - - // Indent horizontal, Lower left arc - $this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih); - $this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270); - - // Indent vertical, Indent arc - $this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r); - $this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90); - - if( $aFillColor != '' ) { - $bc = $this->img->current_color_name; - $this->img->PushColor($aFillColor); - $this->img->FillToBorder($xr-$r,$yl-$r,$bc); - $this->img->PopColor(); - } - - break; - - case 1: // Upper right - - // Bottom line, left & right arc - $this->img->Line($xt+$r,$yl,$xr-$r,$yl); - $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); - $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); - - // Left line, Top left arc - $this->img->Line($xt,$yt+$r,$xt,$yl-$r); - $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); - - // Top line, Top right arc - $this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt); - $this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360); - - // Right line - $this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r); - - // Indent horizontal, Lower right arc - $this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih); - $this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360); - - // Indent vertical, Indent arc - $this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r); - $this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180); - - if( $aFillColor != '' ) { - $bc = $this->img->current_color_name; - $this->img->PushColor($aFillColor); - $this->img->FillToBorder($xt+$r,$yl-$r,$bc); - $this->img->PopColor(); - } - - break; - - case 2: // Lower right - // Top line, Top left & Top right arc - $this->img->Line($xt+$r,$yt,$xr-$r,$yt); - $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); - $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); - - // Left line, Bottom left arc - $this->img->Line($xt,$yt+$r,$xt,$yl-$r); - $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); - - // Bottom line, Bottom right arc - $this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl); - $this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90); - - // Right line - $this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r); - - // Indent horizontal, Lower right arc - $this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih); - $this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90); - - // Indent vertical, Indent arc - $this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r); - $this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270); - - if( $aFillColor != '' ) { - $bc = $this->img->current_color_name; - $this->img->PushColor($aFillColor); - $this->img->FillToBorder($xt+$r,$yt+$r,$bc); - $this->img->PopColor(); - } - - break; - - case 3: // Lower left - // Top line, Top left & Top right arc - $this->img->Line($xt+$r,$yt,$xr-$r,$yt); - $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); - $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); - - // Right line, Bottom right arc - $this->img->Line($xr,$yt+$r,$xr,$yl-$r); - $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); - - // Bottom line, Bottom left arc - $this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl); - $this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180); - - // Left line - $this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r); - - // Indent horizontal, Lower left arc - $this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih); - $this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180); - - // Indent vertical, Indent arc - $this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r); - $this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360); - - if( $aFillColor != '' ) { - $bc = $this->img->current_color_name; - $this->img->PushColor($aFillColor); - $this->img->FillToBorder($xr-$r,$yt+$r,$bc); - $this->img->PopColor(); - } - - break; - } - } -} - - -//=================================================== -// CLASS RectangleText -// Description: Draws a text paragraph inside a -// rounded, possible filled, rectangle. -//=================================================== -class CanvasRectangleText { - private $ix,$iy,$iw,$ih,$ir=4; - private $iTxt,$iColor='black',$iFillColor='',$iFontColor='black'; - private $iParaAlign='center'; - private $iAutoBoxMargin=5; - private $iShadowWidth=3,$iShadowColor=''; - - function __construct($aTxt='',$xl=0,$yt=0,$w=0,$h=0) { - $this->iTxt = new Text($aTxt); - $this->ix = $xl; - $this->iy = $yt; - $this->iw = $w; - $this->ih = $h; - } - - function SetShadow($aColor='gray',$aWidth=3) { - $this->iShadowColor = $aColor; - $this->iShadowWidth = $aWidth; - } - - function SetFont($FontFam,$aFontStyle,$aFontSize=12) { - $this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize); - } - - function SetTxt($aTxt) { - $this->iTxt->Set($aTxt); - } - - function ParagraphAlign($aParaAlign) { - $this->iParaAlign = $aParaAlign; - } - - function SetFillColor($aFillColor) { - $this->iFillColor = $aFillColor; - } - - function SetAutoMargin($aMargin) { - $this->iAutoBoxMargin=$aMargin; - } - - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function SetFontColor($aColor) { - $this->iFontColor = $aColor; - } - - function SetPos($xl=0,$yt=0,$w=0,$h=0) { - $this->ix = $xl; - $this->iy = $yt; - $this->iw = $w; - $this->ih = $h; - } - - function Pos($xl=0,$yt=0,$w=0,$h=0) { - $this->ix = $xl; - $this->iy = $yt; - $this->iw = $w; - $this->ih = $h; - } - - function Set($aTxt,$xl,$yt,$w=0,$h=0) { - $this->iTxt->Set($aTxt); - $this->ix = $xl; - $this->iy = $yt; - $this->iw = $w; - $this->ih = $h; - } - - function SetCornerRadius($aRad=5) { - $this->ir = $aRad; - } - - function Stroke($aImg,$scale) { - - // If coordinates are specifed as negative this means we should - // treat them as abolsute (pixels) coordinates - if( $this->ix > 0 ) { - $this->ix = $scale->TranslateX($this->ix) ; - } - else { - $this->ix = -$this->ix; - } - - if( $this->iy > 0 ) { - $this->iy = $scale->TranslateY($this->iy) ; - } - else { - $this->iy = -$this->iy; - } - - list($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ; - - if( $this->iw == 0 ) - $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin); - if( $this->ih == 0 ) { - $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin); - } - - if( $this->iShadowColor != '' ) { - $aImg->PushColor($this->iShadowColor); - $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth, - $this->iy+$this->iShadowWidth, - $this->ix+$this->iw-1+$this->iShadowWidth, - $this->iy+$this->ih-1+$this->iShadowWidth, - $this->ir); - $aImg->PopColor(); - } - - if( $this->iFillColor != '' ) { - $aImg->PushColor($this->iFillColor); - $aImg->FilledRoundedRectangle($this->ix,$this->iy, - $this->ix+$this->iw-1, - $this->iy+$this->ih-1, - $this->ir); - $aImg->PopColor(); - } - - if( $this->iColor != '' ) { - $aImg->PushColor($this->iColor); - $aImg->RoundedRectangle($this->ix,$this->iy, - $this->ix+$this->iw-1, - $this->iy+$this->ih-1, - $this->ir); - $aImg->PopColor(); - } - - $this->iTxt->Align('center','center'); - $this->iTxt->ParagraphAlign($this->iParaAlign); - $this->iTxt->SetColor($this->iFontColor); - $this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2); - - return array($this->iw, $this->ih); - - } - -} - - +g = $graph; + $this->w = $graph->img->width; + $this->h = $graph->img->height; + $this->ixmin = $xmin; + $this->ixmax = $xmax; + $this->iymin = $ymin; + $this->iymax = $ymax; + } + + function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) { + $this->ixmin = $xmin; + $this->ixmax = $xmax; + $this->iymin = $ymin; + $this->iymax = $ymax; + } + + function Get() { + return array($this->ixmin,$this->ixmax,$this->iymin,$this->iymax); + } + + function Translate($x,$y) { + $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); + $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); + return array($xp,$yp); + } + + function TranslateX($x) { + $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); + return $xp; + } + + function TranslateY($y) { + $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); + return $yp; + } + +} + + +//=================================================== +// CLASS Shape +// Description: Methods to draw shapes on canvas +//=================================================== +class Shape { + private $img,$scale; + + function __construct($aGraph,$scale) { + $this->img = $aGraph->img; + $this->img->SetColor('black'); + $this->scale = $scale; + } + + function SetColor($aColor) { + $this->img->SetColor($aColor); + } + + function Line($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->Line($x1,$y1,$x2,$y2); + } + + function SetLineWeight($aWeight) { + $this->img->SetLineWeight($aWeight); + } + + function Polygon($p,$aClosed=false) { + $n=count($p); + for($i=0; $i < $n; $i+=2 ) { + $p[$i] = $this->scale->TranslateX($p[$i]); + $p[$i+1] = $this->scale->TranslateY($p[$i+1]); + } + $this->img->Polygon($p,$aClosed); + } + + function FilledPolygon($p) { + $n=count($p); + for($i=0; $i < $n; $i+=2 ) { + $p[$i] = $this->scale->TranslateX($p[$i]); + $p[$i+1] = $this->scale->TranslateY($p[$i+1]); + } + $this->img->FilledPolygon($p); + } + + + // Draw a bezier curve with defining points in the $aPnts array + // using $aSteps steps. + // 0=x0, 1=y0 + // 2=x1, 3=y1 + // 4=x2, 5=y2 + // 6=x3, 7=y3 + function Bezier($p,$aSteps=40) { + $x0 = $p[0]; + $y0 = $p[1]; + // Calculate coefficients + $cx = 3*($p[2]-$p[0]); + $bx = 3*($p[4]-$p[2])-$cx; + $ax = $p[6]-$p[0]-$cx-$bx; + $cy = 3*($p[3]-$p[1]); + $by = 3*($p[5]-$p[3])-$cy; + $ay = $p[7]-$p[1]-$cy-$by; + + // Step size + $delta = 1.0/$aSteps; + + $x_old = $x0; + $y_old = $y0; + for($t=$delta; $t<=1.0; $t+=$delta) { + $tt = $t*$t; $ttt=$tt*$t; + $x = $ax*$ttt + $bx*$tt + $cx*$t + $x0; + $y = $ay*$ttt + $by*$tt + $cy*$t + $y0; + $this->Line($x_old,$y_old,$x,$y); + $x_old = $x; + $y_old = $y; + } + $this->Line($x_old,$y_old,$p[6],$p[7]); + } + + function Rectangle($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->Rectangle($x1,$y1,$x2,$y2); + } + + function FilledRectangle($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->FilledRectangle($x1,$y1,$x2,$y2); + } + + function Circle($x1,$y1,$r) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + if( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->Circle($x1,$y1,$r); + } + + function FilledCircle($x1,$y1,$r) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + if( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->FilledCircle($x1,$y1,$r); + } + + function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + + if( $r == null ) + $r = 5; + elseif( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r); + } + + function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + + if( $r == null ) + $r = 5; + elseif( $r > 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r); + } + + function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + if( $shadow_width == null ) + $shadow_width=4; + else + $shadow_width=$this->scale->TranslateX($shadow_width); + $this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color); + } + + function SetTextAlign($halign,$valign="bottom") { + $this->img->SetTextAlign($halign,$valign="bottom"); + } + + function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align="left") { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + $this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align); + } + + // A rounded rectangle where one of the corner has been moved "into" the + // rectangle 'iw' width and 'ih' height. Corners: + // 0=Top left, 1=top right, 2=bottom right, 3=bottom left + function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor="",$r=4) { + + list($xt,$yt) = $this->scale->Translate($xt,$yt); + list($w,$h) = $this->scale->Translate($w,$h); + list($iw,$ih) = $this->scale->Translate($iw,$ih); + + $xr = $xt + $w - 0; + $yl = $yt + $h - 0; + + switch( $aCorner ) { + case 0: // Upper left + + // Bottom line, left & right arc + $this->img->Line($xt+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Right line, Top right arc + $this->img->Line($xr,$yt+$r,$xr,$yl-$r); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Top line, Top left arc + $this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270); + + // Left line + $this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r); + + // Indent horizontal, Lower left arc + $this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih); + $this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270); + + // Indent vertical, Indent arc + $this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r); + $this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xr-$r,$yl-$r,$bc); + $this->img->PopColor(); + } + + break; + + case 1: // Upper right + + // Bottom line, left & right arc + $this->img->Line($xt+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Left line, Top left arc + $this->img->Line($xt,$yt+$r,$xt,$yl-$r); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + + // Top line, Top right arc + $this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt); + $this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360); + + // Right line + $this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r); + + // Indent horizontal, Lower right arc + $this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih); + $this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360); + + // Indent vertical, Indent arc + $this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r); + $this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xt+$r,$yl-$r,$bc); + $this->img->PopColor(); + } + + break; + + case 2: // Lower right + // Top line, Top left & Top right arc + $this->img->Line($xt+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Left line, Bottom left arc + $this->img->Line($xt,$yt+$r,$xt,$yl-$r); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + + // Bottom line, Bottom right arc + $this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl); + $this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90); + + // Right line + $this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r); + + // Indent horizontal, Lower right arc + $this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih); + $this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90); + + // Indent vertical, Indent arc + $this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r); + $this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xt+$r,$yt+$r,$bc); + $this->img->PopColor(); + } + + break; + + case 3: // Lower left + // Top line, Top left & Top right arc + $this->img->Line($xt+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Right line, Bottom right arc + $this->img->Line($xr,$yt+$r,$xr,$yl-$r); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Bottom line, Bottom left arc + $this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180); + + // Left line + $this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r); + + // Indent horizontal, Lower left arc + $this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih); + $this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180); + + // Indent vertical, Indent arc + $this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r); + $this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xr-$r,$yt+$r,$bc); + $this->img->PopColor(); + } + + break; + } + } +} + + +//=================================================== +// CLASS RectangleText +// Description: Draws a text paragraph inside a +// rounded, possible filled, rectangle. +//=================================================== +class CanvasRectangleText { + private $ix,$iy,$iw,$ih,$ir=4; + private $iTxt,$iColor='black',$iFillColor='',$iFontColor='black'; + private $iParaAlign='center'; + private $iAutoBoxMargin=5; + private $iShadowWidth=3,$iShadowColor=''; + + function __construct($aTxt='',$xl=0,$yt=0,$w=0,$h=0) { + $this->iTxt = new Text($aTxt); + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function SetShadow($aColor='gray',$aWidth=3) { + $this->iShadowColor = $aColor; + $this->iShadowWidth = $aWidth; + } + + function SetFont($FontFam,$aFontStyle,$aFontSize=12) { + $this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize); + } + + function SetTxt($aTxt) { + $this->iTxt->Set($aTxt); + } + + function ParagraphAlign($aParaAlign) { + $this->iParaAlign = $aParaAlign; + } + + function SetFillColor($aFillColor) { + $this->iFillColor = $aFillColor; + } + + function SetAutoMargin($aMargin) { + $this->iAutoBoxMargin=$aMargin; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetFontColor($aColor) { + $this->iFontColor = $aColor; + } + + function SetPos($xl=0,$yt=0,$w=0,$h=0) { + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function Pos($xl=0,$yt=0,$w=0,$h=0) { + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function Set($aTxt,$xl,$yt,$w=0,$h=0) { + $this->iTxt->Set($aTxt); + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function SetCornerRadius($aRad=5) { + $this->ir = $aRad; + } + + function Stroke($aImg,$scale) { + + // If coordinates are specifed as negative this means we should + // treat them as abolsute (pixels) coordinates + if( $this->ix > 0 ) { + $this->ix = $scale->TranslateX($this->ix) ; + } + else { + $this->ix = -$this->ix; + } + + if( $this->iy > 0 ) { + $this->iy = $scale->TranslateY($this->iy) ; + } + else { + $this->iy = -$this->iy; + } + + list($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ; + + if( $this->iw == 0 ) + $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin); + if( $this->ih == 0 ) { + $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin); + } + + if( $this->iShadowColor != '' ) { + $aImg->PushColor($this->iShadowColor); + $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth, + $this->iy+$this->iShadowWidth, + $this->ix+$this->iw-1+$this->iShadowWidth, + $this->iy+$this->ih-1+$this->iShadowWidth, + $this->ir); + $aImg->PopColor(); + } + + if( $this->iFillColor != '' ) { + $aImg->PushColor($this->iFillColor); + $aImg->FilledRoundedRectangle($this->ix,$this->iy, + $this->ix+$this->iw-1, + $this->iy+$this->ih-1, + $this->ir); + $aImg->PopColor(); + } + + if( $this->iColor != '' ) { + $aImg->PushColor($this->iColor); + $aImg->RoundedRectangle($this->ix,$this->iy, + $this->ix+$this->iw-1, + $this->iy+$this->ih-1, + $this->ir); + $aImg->PopColor(); + } + + $this->iTxt->Align('center','center'); + $this->iTxt->ParagraphAlign($this->iParaAlign); + $this->iTxt->SetColor($this->iFontColor); + $this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2); + + return array($this->iw, $this->ih); + + } + +} + + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_contour.php b/ext/jpgraph-3.0.7/src/jpgraph_contour.php index 0b23cde..76d2f9f 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_contour.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_contour.php @@ -1,587 +1,587 @@ -nbrRows = count($aMatrix); - $this->nbrCols = count($aMatrix[0]); - $this->dataPoints = $aMatrix; - - if( is_array($aIsobars) ) { - // use the isobar values supplied - $this->nbrIsobars = count($aIsobars); - $this->isobarValues = $aIsobars; - } - else { - // Determine the isobar values automatically - $this->nbrIsobars = $aIsobars; - list($min,$max) = $this->getMinMaxVal(); - $stepSize = ($max-$min) / $aIsobars ; - $isobar = $min+$stepSize/2; - for ($i = 0; $i < $aIsobars; $i++) { - $this->isobarValues[$i] = $isobar; - $isobar += $stepSize; - } - } - - if( $aColors !== null && count($aColors) > 0 ) { - - if( !is_array($aColors) ) { - JpGraphError::RaiseL(28001); - //'Third argument to Contour must be an array of colors.' - } - - if( count($aColors) != count($this->isobarValues) ) { - JpGraphError::RaiseL(28002); - //'Number of colors must equal the number of isobar lines specified'; - } - - $this->isobarColors = $aColors; - } - } - - /** - * Flip the plot around the Y-coordinate. This has the same affect as flipping the input - * data matrice - * - * @param $aFlg If true the the vertice in input data matrice position (0,0) corresponds to the top left - * corner of teh plot otherwise it will correspond to the bottom left corner (a horizontal flip) - */ - function SetInvert($aFlg=true) { - $this->invert = $aFlg; - } - - /** - * Find the min and max values in the data matrice - * - * @return array(min_value,max_value) - */ - function getMinMaxVal() { - $min = $this->dataPoints[0][0]; - $max = $this->dataPoints[0][0]; - for ($i = 0; $i < $this->nbrRows; $i++) { - if( ($mi=min($this->dataPoints[$i])) < $min ) $min = $mi; - if( ($ma=max($this->dataPoints[$i])) > $max ) $max = $ma; - } - return array($min,$max); - } - - /** - * Reset the two matrices that keeps track on where the isobars crosses the - * horizontal and vertical edges - */ - function resetEdgeMatrices() { - for ($k = 0; $k < 2; $k++) { - for ($i = 0; $i <= $this->nbrRows; $i++) { - for ($j = 0; $j <= $this->nbrCols; $j++) { - $this->edges[$k][$i][$j] = false; - } - } - } - } - - /** - * Determine if the specified isobar crosses the horizontal edge specified by its row and column - * - * @param $aRow Row index of edge to be checked - * @param $aCol Col index of edge to be checked - * @param $aIsobar Isobar value - * @return true if the isobar is crossing this edge - */ - function isobarHCrossing($aRow,$aCol,$aIsobar) { - - if( $aCol >= $this->nbrCols-1 ) { - JpGraphError::RaiseL(28003,$aCol); - //'ContourPlot Internal Error: isobarHCrossing: Coloumn index too large (%d)' - } - if( $aRow >= $this->nbrRows ) { - JpGraphError::RaiseL(28004,$aRow); - //'ContourPlot Internal Error: isobarHCrossing: Row index too large (%d)' - } - - $v1 = $this->dataPoints[$aRow][$aCol]; - $v2 = $this->dataPoints[$aRow][$aCol+1]; - - return ($aIsobar-$v1)*($aIsobar-$v2) < 0 ; - - } - - /** - * Determine if the specified isobar crosses the vertical edge specified by its row and column - * - * @param $aRow Row index of edge to be checked - * @param $aCol Col index of edge to be checked - * @param $aIsobar Isobar value - * @return true if the isobar is crossing this edge - */ - function isobarVCrossing($aRow,$aCol,$aIsobar) { - - if( $aRow >= $this->nbrRows-1) { - JpGraphError::RaiseL(28005,$aRow); - //'isobarVCrossing: Row index too large - } - if( $aCol >= $this->nbrCols ) { - JpGraphError::RaiseL(28006,$aCol); - //'isobarVCrossing: Col index too large - } - - $v1 = $this->dataPoints[$aRow][$aCol]; - $v2 = $this->dataPoints[$aRow+1][$aCol]; - - return ($aIsobar-$v1)*($aIsobar-$v2) < 0 ; - - } - - /** - * Determine all edges, horizontal and vertical that the specified isobar crosses. The crossings - * are recorded in the two edge matrices. - * - * @param $aIsobar The value of the isobar to be checked - */ - function determineIsobarEdgeCrossings($aIsobar) { - - $ib = $this->isobarValues[$aIsobar]; - - for ($i = 0; $i < $this->nbrRows-1; $i++) { - for ($j = 0; $j < $this->nbrCols-1; $j++) { - $this->edges[HORIZ_EDGE][$i][$j] = $this->isobarHCrossing($i,$j,$ib); - $this->edges[VERT_EDGE][$i][$j] = $this->isobarVCrossing($i,$j,$ib); - } - } - - // We now have the bottom and rightmost edges unsearched - for ($i = 0; $i < $this->nbrRows-1; $i++) { - $this->edges[VERT_EDGE][$i][$j] = $this->isobarVCrossing($i,$this->nbrCols-1,$ib); - } - for ($j = 0; $j < $this->nbrCols-1; $j++) { - $this->edges[HORIZ_EDGE][$i][$j] = $this->isobarHCrossing($this->nbrRows-1,$j,$ib); - } - - } - - /** - * Return the normalized coordinates for the crossing of the specified edge with the specified - * isobar- The crossing is simpy detrmined with a linear interpolation between the two vertices - * on each side of the edge and the value of the isobar - * - * @param $aRow Row of edge - * @param $aCol Column of edge - * @param $aEdgeDir Determine if this is a horizontal or vertical edge - * @param $ib The isobar value - * @return unknown_type - */ - function getCrossingCoord($aRow,$aCol,$aEdgeDir,$aIsobarVal) { - - // In order to avoid numerical problem when two vertices are very close - // we have to check and avoid dividing by close to zero denumerator. - if( $aEdgeDir == HORIZ_EDGE ) { - $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow][$aCol+1]); - if( $d > 0.001 ) { - $xcoord = $aCol + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; - } - else { - $xcoord = $aCol; - } - $ycoord = $aRow; - } - else { - $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow+1][$aCol]); - if( $d > 0.001 ) { - $ycoord = $aRow + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; - } - else { - $ycoord = $aRow; - } - $xcoord = $aCol; - } - if( $this->invert ) { - $ycoord = $this->nbrRows-1 - $ycoord; - } - return array($xcoord,$ycoord); - - } - - /** - * In order to avoid all kinds of unpleasent extra checks and complex boundary - * controls for the degenerated case where the contour levels exactly crosses - * one of the vertices we add a very small delta (0.1%) to the data point value. - * This has no visible affect but it makes the code sooooo much cleaner. - * - */ - function adjustDataPointValues() { - - $ni = count($this->isobarValues); - for ($k = 0; $k < $ni; $k++) { - $ib = $this->isobarValues[$k]; - for ($row = 0 ; $row < $this->nbrRows-1; ++$row) { - for ($col = 0 ; $col < $this->nbrCols-1; ++$col ) { - if( abs($this->dataPoints[$row][$col] - $ib) < 0.0001 ) { - $this->dataPoints[$row][$col] += $this->dataPoints[$row][$col]*0.001; - } - } - } - } - - } - - /** - * @param $aFlg - * @param $aBW - * @return unknown_type - */ - function UseHighContrastColor($aFlg=true,$aBW=false) { - $this->highcontrast = $aFlg; - $this->highcontrastbw = $aBW; - } - - /** - * Calculate suitable colors for each defined isobar - * - */ - function CalculateColors() { - if ( $this->highcontrast ) { - if ( $this->highcontrastbw ) { - for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { - $this->isobarColors[$ib] = 'black'; - } - } - else { - // Use only blue/red scale - $step = round(255/($this->nbrIsobars-1)); - for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { - $this->isobarColors[$ib] = array($ib*$step, 50, 255-$ib*$step); - } - } - } - else { - $n = $this->nbrIsobars; - $v = 0; $step = 1 / ($this->nbrIsobars-1); - for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { - $this->isobarColors[$ib] = RGB::GetSpectrum($v); - $v += $step; - } - } - } - - /** - * This is where the main work is done. For each isobar the crossing of the edges are determined - * and then each cell is analyzed to find the 0, 2 or 4 crossings. Then the normalized coordinate - * for the crossings are determined and pushed on to the isobar stack. When the method is finished - * the $isobarCoord will hold one arrayfor each isobar where all the line segments that makes - * up the contour plot are stored. - * - * @return array( $isobarCoord, $isobarValues, $isobarColors ) - */ - function getIsobars() { - - $this->adjustDataPointValues(); - - for ($isobar = 0; $isobar < $this->nbrIsobars; $isobar++) { - - $ib = $this->isobarValues[$isobar]; - $this->resetEdgeMatrices(); - $this->determineIsobarEdgeCrossings($isobar); - $this->isobarCoord[$isobar] = array(); - - $ncoord = 0; - - for ($row = 0 ; $row < $this->nbrRows-1; ++$row) { - for ($col = 0 ; $col < $this->nbrCols-1; ++$col ) { - - // Find out how many crossings around the edges - $n = 0; - if ( $this->edges[HORIZ_EDGE][$row][$col] ) $neigh[$n++] = array($row, $col, HORIZ_EDGE); - if ( $this->edges[HORIZ_EDGE][$row+1][$col] ) $neigh[$n++] = array($row+1,$col, HORIZ_EDGE); - if ( $this->edges[VERT_EDGE][$row][$col] ) $neigh[$n++] = array($row, $col, VERT_EDGE); - if ( $this->edges[VERT_EDGE][$row][$col+1] ) $neigh[$n++] = array($row, $col+1,VERT_EDGE); - - if ( $n == 2 ) { - $n1=0; $n2=1; - $this->isobarCoord[$isobar][$ncoord++] = array( - $this->getCrossingCoord($neigh[$n1][0],$neigh[$n1][1],$neigh[$n1][2],$ib), - $this->getCrossingCoord($neigh[$n2][0],$neigh[$n2][1],$neigh[$n2][2],$ib) ); - } - elseif ( $n == 4 ) { - // We must determine how to connect the edges either northwest->southeast or - // northeast->southwest. We do that by calculating the imaginary middle value of - // the cell by averaging the for corners. This will compared with the value of the - // top left corner will help determine the orientation of the ridge/creek - $midval = ($this->dataPoints[$row][$col]+$this->dataPoints[$row][$col+1]+$this->dataPoints[$row+1][$col]+$this->dataPoints[$row+1][$col+1])/4; - $v = $this->dataPoints[$row][$col]; - if( $midval == $ib ) { - // Orientation "+" - $n1=0; $n2=1; $n3=2; $n4=3; - } elseif ( ($midval > $ib && $v > $ib) || ($midval < $ib && $v < $ib) ) { - // Orientation of ridge/valley = "\" - $n1=0; $n2=3; $n3=2; $n4=1; - } elseif ( ($midval > $ib && $v < $ib) || ($midval < $ib && $v > $ib) ) { - // Orientation of ridge/valley = "/" - $n1=0; $n2=2; $n3=3; $n4=1; - } - - $this->isobarCoord[$isobar][$ncoord++] = array( - $this->getCrossingCoord($neigh[$n1][0],$neigh[$n1][1],$neigh[$n1][2],$ib), - $this->getCrossingCoord($neigh[$n2][0],$neigh[$n2][1],$neigh[$n2][2],$ib) ); - - $this->isobarCoord[$isobar][$ncoord++] = array( - $this->getCrossingCoord($neigh[$n3][0],$neigh[$n3][1],$neigh[$n3][2],$ib), - $this->getCrossingCoord($neigh[$n4][0],$neigh[$n4][1],$neigh[$n4][2],$ib) ); - - } - } - } - } - - if( count($this->isobarColors) == 0 ) { - // No manually specified colors. Calculate them automatically. - $this->CalculateColors(); - } - return array( $this->isobarCoord, $this->isobarValues, $this->isobarColors ); - } -} - - -/** - * This class represent a plotting of a contour outline of data given as a X-Y matrice - * - */ -class ContourPlot extends Plot { - - private $contour, $contourCoord, $contourVal, $contourColor; - private $nbrCountours = 0 ; - private $dataMatrix = array(); - private $invertLegend = false; - private $interpFactor = 1; - private $flipData = false; - private $isobar = 10; - private $showLegend = false; - private $highcontrast = false, $highcontrastbw = false; - private $manualIsobarColors = array(); - - /** - * Construct a contour plotting algorithm. The end result of the algorithm is a sequence of - * line segments for each isobar given as two vertices. - * - * @param $aDataMatrix The Z-data to be used - * @param $aIsobar A mixed variable, if it is an integer then this specified the number of isobars to use. - * The values of the isobars are automatically detrmined to be equ-spaced between the min/max value of the - * data. If it is an array then it explicetely gives the isobar values - * @param $aInvert By default the matrice with row index 0 corresponds to Y-value 0, i.e. in the bottom of - * the plot. If this argument is true then the row with the highest index in the matrice corresponds to - * Y-value 0. In affect flipping the matrice around an imaginary horizontal axis. - * @param $aHighContrast Use high contrast colors (blue/red:ish) - * @param $aHighContrastBW Use only black colors for contours - * @return an instance of the contour plot algorithm - */ - function __construct($aDataMatrix, $aIsobar=10, $aFactor=1, $aInvert=false, $aIsobarColors=array()) { - - $this->dataMatrix = $aDataMatrix; - $this->flipData = $aInvert; - $this->isobar = $aIsobar; - $this->interpFactor = $aFactor; - - if ( $this->interpFactor > 1 ) { - - if( $this->interpFactor > 5 ) { - JpGraphError::RaiseL(28007);// ContourPlot interpolation factor is too large (>5) - } - - $ip = new MeshInterpolate(); - $this->dataMatrix = $ip->Linear($this->dataMatrix, $this->interpFactor); - } - - $this->contour = new Contour($this->dataMatrix,$this->isobar,$aIsobarColors); - - if( is_array($aIsobar) ) - $this->nbrContours = count($aIsobar); - else - $this->nbrContours = $aIsobar; - } - - - /** - * Flipe the data around the center - * - * @param $aFlg - * - */ - function SetInvert($aFlg=true) { - $this->flipData = $aFlg; - } - - /** - * Set the colors for the isobar lines - * - * @param $aColorArray - * - */ - function SetIsobarColors($aColorArray) { - $this->manualIsobarColors = $aColorArray; - } - - /** - * Show the legend - * - * @param $aFlg true if the legend should be shown - * - */ - function ShowLegend($aFlg=true) { - $this->showLegend = $aFlg; - } - - - /** - * @param $aFlg true if the legend should start with the lowest isobar on top - * @return unknown_type - */ - function Invertlegend($aFlg=true) { - $this->invertLegend = $aFlg; - } - - /* Internal method. Give the min value to be used for the scaling - * - */ - function Min() { - return array(0,0); - } - - /* Internal method. Give the max value to be used for the scaling - * - */ - function Max() { - return array(count($this->dataMatrix[0])-1,count($this->dataMatrix)-1); - } - - /** - * Internal ramewrok method to setup the legend to be used for this plot. - * @param $aGraph The parent graph class - */ - function Legend($aGraph) { - - if( ! $this->showLegend ) - return; - - if( $this->invertLegend ) { - for ($i = 0; $i < $this->nbrContours; $i++) { - $aGraph->legend->Add(sprintf('%.1f',$this->contourVal[$i]), $this->contourColor[$i]); - } - } - else { - for ($i = $this->nbrContours-1; $i >= 0 ; $i--) { - $aGraph->legend->Add(sprintf('%.1f',$this->contourVal[$i]), $this->contourColor[$i]); - } - } - } - - - /** - * Framework function which gets called before the Stroke() method is called - * - * @see Plot#PreScaleSetup($aGraph) - * - */ - function PreScaleSetup($aGraph) { - $xn = count($this->dataMatrix[0])-1; - $yn = count($this->dataMatrix)-1; - - $aGraph->xaxis->scale->Update($aGraph->img,0,$xn); - $aGraph->yaxis->scale->Update($aGraph->img,0,$yn); - - $this->contour->SetInvert($this->flipData); - list($this->contourCoord,$this->contourVal,$this->contourColor) = $this->contour->getIsobars(); - } - - /** - * Use high contrast color schema - * - * @param $aFlg True, to use high contrast color - * @param $aBW True, Use only black and white color schema - */ - function UseHighContrastColor($aFlg=true,$aBW=false) { - $this->highcontrast = $aFlg; - $this->highcontrastbw = $aBW; - $this->contour->UseHighContrastColor($this->highcontrast,$this->highcontrastbw); - } - - /** - * Internal method. Stroke the contour plot to the graph - * - * @param $img Image handler - * @param $xscale Instance of the xscale to use - * @param $yscale Instance of the yscale to use - */ - function Stroke($img,$xscale,$yscale) { - - if( count($this->manualIsobarColors) > 0 ) { - $this->contourColor = $this->manualIsobarColors; - if( count($this->manualIsobarColors) != $this->nbrContours ) { - JpGraphError::RaiseL(28002); - } - } - - $img->SetLineWeight($this->line_weight); - - for ($c = 0; $c < $this->nbrContours; $c++) { - - $img->SetColor( $this->contourColor[$c] ); - - $n = count($this->contourCoord[$c]); - $i = 0; - while ( $i < $n ) { - list($x1,$y1) = $this->contourCoord[$c][$i][0]; - $x1t = $xscale->Translate($x1); - $y1t = $yscale->Translate($y1); - - list($x2,$y2) = $this->contourCoord[$c][$i++][1]; - $x2t = $xscale->Translate($x2); - $y2t = $yscale->Translate($y2); - - $img->Line($x1t,$y1t,$x2t,$y2t); - } - - } - } - -} - -// EOF -?> +nbrRows = count($aMatrix); + $this->nbrCols = count($aMatrix[0]); + $this->dataPoints = $aMatrix; + + if( is_array($aIsobars) ) { + // use the isobar values supplied + $this->nbrIsobars = count($aIsobars); + $this->isobarValues = $aIsobars; + } + else { + // Determine the isobar values automatically + $this->nbrIsobars = $aIsobars; + list($min,$max) = $this->getMinMaxVal(); + $stepSize = ($max-$min) / $aIsobars ; + $isobar = $min+$stepSize/2; + for ($i = 0; $i < $aIsobars; $i++) { + $this->isobarValues[$i] = $isobar; + $isobar += $stepSize; + } + } + + if( $aColors !== null && count($aColors) > 0 ) { + + if( !is_array($aColors) ) { + JpGraphError::RaiseL(28001); + //'Third argument to Contour must be an array of colors.' + } + + if( count($aColors) != count($this->isobarValues) ) { + JpGraphError::RaiseL(28002); + //'Number of colors must equal the number of isobar lines specified'; + } + + $this->isobarColors = $aColors; + } + } + + /** + * Flip the plot around the Y-coordinate. This has the same affect as flipping the input + * data matrice + * + * @param $aFlg If true the the vertice in input data matrice position (0,0) corresponds to the top left + * corner of teh plot otherwise it will correspond to the bottom left corner (a horizontal flip) + */ + function SetInvert($aFlg=true) { + $this->invert = $aFlg; + } + + /** + * Find the min and max values in the data matrice + * + * @return array(min_value,max_value) + */ + function getMinMaxVal() { + $min = $this->dataPoints[0][0]; + $max = $this->dataPoints[0][0]; + for ($i = 0; $i < $this->nbrRows; $i++) { + if( ($mi=min($this->dataPoints[$i])) < $min ) $min = $mi; + if( ($ma=max($this->dataPoints[$i])) > $max ) $max = $ma; + } + return array($min,$max); + } + + /** + * Reset the two matrices that keeps track on where the isobars crosses the + * horizontal and vertical edges + */ + function resetEdgeMatrices() { + for ($k = 0; $k < 2; $k++) { + for ($i = 0; $i <= $this->nbrRows; $i++) { + for ($j = 0; $j <= $this->nbrCols; $j++) { + $this->edges[$k][$i][$j] = false; + } + } + } + } + + /** + * Determine if the specified isobar crosses the horizontal edge specified by its row and column + * + * @param $aRow Row index of edge to be checked + * @param $aCol Col index of edge to be checked + * @param $aIsobar Isobar value + * @return true if the isobar is crossing this edge + */ + function isobarHCrossing($aRow,$aCol,$aIsobar) { + + if( $aCol >= $this->nbrCols-1 ) { + JpGraphError::RaiseL(28003,$aCol); + //'ContourPlot Internal Error: isobarHCrossing: Coloumn index too large (%d)' + } + if( $aRow >= $this->nbrRows ) { + JpGraphError::RaiseL(28004,$aRow); + //'ContourPlot Internal Error: isobarHCrossing: Row index too large (%d)' + } + + $v1 = $this->dataPoints[$aRow][$aCol]; + $v2 = $this->dataPoints[$aRow][$aCol+1]; + + return ($aIsobar-$v1)*($aIsobar-$v2) < 0 ; + + } + + /** + * Determine if the specified isobar crosses the vertical edge specified by its row and column + * + * @param $aRow Row index of edge to be checked + * @param $aCol Col index of edge to be checked + * @param $aIsobar Isobar value + * @return true if the isobar is crossing this edge + */ + function isobarVCrossing($aRow,$aCol,$aIsobar) { + + if( $aRow >= $this->nbrRows-1) { + JpGraphError::RaiseL(28005,$aRow); + //'isobarVCrossing: Row index too large + } + if( $aCol >= $this->nbrCols ) { + JpGraphError::RaiseL(28006,$aCol); + //'isobarVCrossing: Col index too large + } + + $v1 = $this->dataPoints[$aRow][$aCol]; + $v2 = $this->dataPoints[$aRow+1][$aCol]; + + return ($aIsobar-$v1)*($aIsobar-$v2) < 0 ; + + } + + /** + * Determine all edges, horizontal and vertical that the specified isobar crosses. The crossings + * are recorded in the two edge matrices. + * + * @param $aIsobar The value of the isobar to be checked + */ + function determineIsobarEdgeCrossings($aIsobar) { + + $ib = $this->isobarValues[$aIsobar]; + + for ($i = 0; $i < $this->nbrRows-1; $i++) { + for ($j = 0; $j < $this->nbrCols-1; $j++) { + $this->edges[HORIZ_EDGE][$i][$j] = $this->isobarHCrossing($i,$j,$ib); + $this->edges[VERT_EDGE][$i][$j] = $this->isobarVCrossing($i,$j,$ib); + } + } + + // We now have the bottom and rightmost edges unsearched + for ($i = 0; $i < $this->nbrRows-1; $i++) { + $this->edges[VERT_EDGE][$i][$j] = $this->isobarVCrossing($i,$this->nbrCols-1,$ib); + } + for ($j = 0; $j < $this->nbrCols-1; $j++) { + $this->edges[HORIZ_EDGE][$i][$j] = $this->isobarHCrossing($this->nbrRows-1,$j,$ib); + } + + } + + /** + * Return the normalized coordinates for the crossing of the specified edge with the specified + * isobar- The crossing is simpy detrmined with a linear interpolation between the two vertices + * on each side of the edge and the value of the isobar + * + * @param $aRow Row of edge + * @param $aCol Column of edge + * @param $aEdgeDir Determine if this is a horizontal or vertical edge + * @param $ib The isobar value + * @return unknown_type + */ + function getCrossingCoord($aRow,$aCol,$aEdgeDir,$aIsobarVal) { + + // In order to avoid numerical problem when two vertices are very close + // we have to check and avoid dividing by close to zero denumerator. + if( $aEdgeDir == HORIZ_EDGE ) { + $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow][$aCol+1]); + if( $d > 0.001 ) { + $xcoord = $aCol + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; + } + else { + $xcoord = $aCol; + } + $ycoord = $aRow; + } + else { + $d = abs($this->dataPoints[$aRow][$aCol] - $this->dataPoints[$aRow+1][$aCol]); + if( $d > 0.001 ) { + $ycoord = $aRow + abs($aIsobarVal - $this->dataPoints[$aRow][$aCol]) / $d; + } + else { + $ycoord = $aRow; + } + $xcoord = $aCol; + } + if( $this->invert ) { + $ycoord = $this->nbrRows-1 - $ycoord; + } + return array($xcoord,$ycoord); + + } + + /** + * In order to avoid all kinds of unpleasent extra checks and complex boundary + * controls for the degenerated case where the contour levels exactly crosses + * one of the vertices we add a very small delta (0.1%) to the data point value. + * This has no visible affect but it makes the code sooooo much cleaner. + * + */ + function adjustDataPointValues() { + + $ni = count($this->isobarValues); + for ($k = 0; $k < $ni; $k++) { + $ib = $this->isobarValues[$k]; + for ($row = 0 ; $row < $this->nbrRows-1; ++$row) { + for ($col = 0 ; $col < $this->nbrCols-1; ++$col ) { + if( abs($this->dataPoints[$row][$col] - $ib) < 0.0001 ) { + $this->dataPoints[$row][$col] += $this->dataPoints[$row][$col]*0.001; + } + } + } + } + + } + + /** + * @param $aFlg + * @param $aBW + * @return unknown_type + */ + function UseHighContrastColor($aFlg=true,$aBW=false) { + $this->highcontrast = $aFlg; + $this->highcontrastbw = $aBW; + } + + /** + * Calculate suitable colors for each defined isobar + * + */ + function CalculateColors() { + if ( $this->highcontrast ) { + if ( $this->highcontrastbw ) { + for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { + $this->isobarColors[$ib] = 'black'; + } + } + else { + // Use only blue/red scale + $step = round(255/($this->nbrIsobars-1)); + for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { + $this->isobarColors[$ib] = array($ib*$step, 50, 255-$ib*$step); + } + } + } + else { + $n = $this->nbrIsobars; + $v = 0; $step = 1 / ($this->nbrIsobars-1); + for ($ib = 0; $ib < $this->nbrIsobars; $ib++) { + $this->isobarColors[$ib] = RGB::GetSpectrum($v); + $v += $step; + } + } + } + + /** + * This is where the main work is done. For each isobar the crossing of the edges are determined + * and then each cell is analyzed to find the 0, 2 or 4 crossings. Then the normalized coordinate + * for the crossings are determined and pushed on to the isobar stack. When the method is finished + * the $isobarCoord will hold one arrayfor each isobar where all the line segments that makes + * up the contour plot are stored. + * + * @return array( $isobarCoord, $isobarValues, $isobarColors ) + */ + function getIsobars() { + + $this->adjustDataPointValues(); + + for ($isobar = 0; $isobar < $this->nbrIsobars; $isobar++) { + + $ib = $this->isobarValues[$isobar]; + $this->resetEdgeMatrices(); + $this->determineIsobarEdgeCrossings($isobar); + $this->isobarCoord[$isobar] = array(); + + $ncoord = 0; + + for ($row = 0 ; $row < $this->nbrRows-1; ++$row) { + for ($col = 0 ; $col < $this->nbrCols-1; ++$col ) { + + // Find out how many crossings around the edges + $n = 0; + if ( $this->edges[HORIZ_EDGE][$row][$col] ) $neigh[$n++] = array($row, $col, HORIZ_EDGE); + if ( $this->edges[HORIZ_EDGE][$row+1][$col] ) $neigh[$n++] = array($row+1,$col, HORIZ_EDGE); + if ( $this->edges[VERT_EDGE][$row][$col] ) $neigh[$n++] = array($row, $col, VERT_EDGE); + if ( $this->edges[VERT_EDGE][$row][$col+1] ) $neigh[$n++] = array($row, $col+1,VERT_EDGE); + + if ( $n == 2 ) { + $n1=0; $n2=1; + $this->isobarCoord[$isobar][$ncoord++] = array( + $this->getCrossingCoord($neigh[$n1][0],$neigh[$n1][1],$neigh[$n1][2],$ib), + $this->getCrossingCoord($neigh[$n2][0],$neigh[$n2][1],$neigh[$n2][2],$ib) ); + } + elseif ( $n == 4 ) { + // We must determine how to connect the edges either northwest->southeast or + // northeast->southwest. We do that by calculating the imaginary middle value of + // the cell by averaging the for corners. This will compared with the value of the + // top left corner will help determine the orientation of the ridge/creek + $midval = ($this->dataPoints[$row][$col]+$this->dataPoints[$row][$col+1]+$this->dataPoints[$row+1][$col]+$this->dataPoints[$row+1][$col+1])/4; + $v = $this->dataPoints[$row][$col]; + if( $midval == $ib ) { + // Orientation "+" + $n1=0; $n2=1; $n3=2; $n4=3; + } elseif ( ($midval > $ib && $v > $ib) || ($midval < $ib && $v < $ib) ) { + // Orientation of ridge/valley = "\" + $n1=0; $n2=3; $n3=2; $n4=1; + } elseif ( ($midval > $ib && $v < $ib) || ($midval < $ib && $v > $ib) ) { + // Orientation of ridge/valley = "/" + $n1=0; $n2=2; $n3=3; $n4=1; + } + + $this->isobarCoord[$isobar][$ncoord++] = array( + $this->getCrossingCoord($neigh[$n1][0],$neigh[$n1][1],$neigh[$n1][2],$ib), + $this->getCrossingCoord($neigh[$n2][0],$neigh[$n2][1],$neigh[$n2][2],$ib) ); + + $this->isobarCoord[$isobar][$ncoord++] = array( + $this->getCrossingCoord($neigh[$n3][0],$neigh[$n3][1],$neigh[$n3][2],$ib), + $this->getCrossingCoord($neigh[$n4][0],$neigh[$n4][1],$neigh[$n4][2],$ib) ); + + } + } + } + } + + if( count($this->isobarColors) == 0 ) { + // No manually specified colors. Calculate them automatically. + $this->CalculateColors(); + } + return array( $this->isobarCoord, $this->isobarValues, $this->isobarColors ); + } +} + + +/** + * This class represent a plotting of a contour outline of data given as a X-Y matrice + * + */ +class ContourPlot extends Plot { + + private $contour, $contourCoord, $contourVal, $contourColor; + private $nbrCountours = 0 ; + private $dataMatrix = array(); + private $invertLegend = false; + private $interpFactor = 1; + private $flipData = false; + private $isobar = 10; + private $showLegend = false; + private $highcontrast = false, $highcontrastbw = false; + private $manualIsobarColors = array(); + + /** + * Construct a contour plotting algorithm. The end result of the algorithm is a sequence of + * line segments for each isobar given as two vertices. + * + * @param $aDataMatrix The Z-data to be used + * @param $aIsobar A mixed variable, if it is an integer then this specified the number of isobars to use. + * The values of the isobars are automatically detrmined to be equ-spaced between the min/max value of the + * data. If it is an array then it explicetely gives the isobar values + * @param $aInvert By default the matrice with row index 0 corresponds to Y-value 0, i.e. in the bottom of + * the plot. If this argument is true then the row with the highest index in the matrice corresponds to + * Y-value 0. In affect flipping the matrice around an imaginary horizontal axis. + * @param $aHighContrast Use high contrast colors (blue/red:ish) + * @param $aHighContrastBW Use only black colors for contours + * @return an instance of the contour plot algorithm + */ + function __construct($aDataMatrix, $aIsobar=10, $aFactor=1, $aInvert=false, $aIsobarColors=array()) { + + $this->dataMatrix = $aDataMatrix; + $this->flipData = $aInvert; + $this->isobar = $aIsobar; + $this->interpFactor = $aFactor; + + if ( $this->interpFactor > 1 ) { + + if( $this->interpFactor > 5 ) { + JpGraphError::RaiseL(28007);// ContourPlot interpolation factor is too large (>5) + } + + $ip = new MeshInterpolate(); + $this->dataMatrix = $ip->Linear($this->dataMatrix, $this->interpFactor); + } + + $this->contour = new Contour($this->dataMatrix,$this->isobar,$aIsobarColors); + + if( is_array($aIsobar) ) + $this->nbrContours = count($aIsobar); + else + $this->nbrContours = $aIsobar; + } + + + /** + * Flipe the data around the center + * + * @param $aFlg + * + */ + function SetInvert($aFlg=true) { + $this->flipData = $aFlg; + } + + /** + * Set the colors for the isobar lines + * + * @param $aColorArray + * + */ + function SetIsobarColors($aColorArray) { + $this->manualIsobarColors = $aColorArray; + } + + /** + * Show the legend + * + * @param $aFlg true if the legend should be shown + * + */ + function ShowLegend($aFlg=true) { + $this->showLegend = $aFlg; + } + + + /** + * @param $aFlg true if the legend should start with the lowest isobar on top + * @return unknown_type + */ + function Invertlegend($aFlg=true) { + $this->invertLegend = $aFlg; + } + + /* Internal method. Give the min value to be used for the scaling + * + */ + function Min() { + return array(0,0); + } + + /* Internal method. Give the max value to be used for the scaling + * + */ + function Max() { + return array(count($this->dataMatrix[0])-1,count($this->dataMatrix)-1); + } + + /** + * Internal ramewrok method to setup the legend to be used for this plot. + * @param $aGraph The parent graph class + */ + function Legend($aGraph) { + + if( ! $this->showLegend ) + return; + + if( $this->invertLegend ) { + for ($i = 0; $i < $this->nbrContours; $i++) { + $aGraph->legend->Add(sprintf('%.1f',$this->contourVal[$i]), $this->contourColor[$i]); + } + } + else { + for ($i = $this->nbrContours-1; $i >= 0 ; $i--) { + $aGraph->legend->Add(sprintf('%.1f',$this->contourVal[$i]), $this->contourColor[$i]); + } + } + } + + + /** + * Framework function which gets called before the Stroke() method is called + * + * @see Plot#PreScaleSetup($aGraph) + * + */ + function PreScaleSetup($aGraph) { + $xn = count($this->dataMatrix[0])-1; + $yn = count($this->dataMatrix)-1; + + $aGraph->xaxis->scale->Update($aGraph->img,0,$xn); + $aGraph->yaxis->scale->Update($aGraph->img,0,$yn); + + $this->contour->SetInvert($this->flipData); + list($this->contourCoord,$this->contourVal,$this->contourColor) = $this->contour->getIsobars(); + } + + /** + * Use high contrast color schema + * + * @param $aFlg True, to use high contrast color + * @param $aBW True, Use only black and white color schema + */ + function UseHighContrastColor($aFlg=true,$aBW=false) { + $this->highcontrast = $aFlg; + $this->highcontrastbw = $aBW; + $this->contour->UseHighContrastColor($this->highcontrast,$this->highcontrastbw); + } + + /** + * Internal method. Stroke the contour plot to the graph + * + * @param $img Image handler + * @param $xscale Instance of the xscale to use + * @param $yscale Instance of the yscale to use + */ + function Stroke($img,$xscale,$yscale) { + + if( count($this->manualIsobarColors) > 0 ) { + $this->contourColor = $this->manualIsobarColors; + if( count($this->manualIsobarColors) != $this->nbrContours ) { + JpGraphError::RaiseL(28002); + } + } + + $img->SetLineWeight($this->line_weight); + + for ($c = 0; $c < $this->nbrContours; $c++) { + + $img->SetColor( $this->contourColor[$c] ); + + $n = count($this->contourCoord[$c]); + $i = 0; + while ( $i < $n ) { + list($x1,$y1) = $this->contourCoord[$c][$i][0]; + $x1t = $xscale->Translate($x1); + $y1t = $yscale->Translate($y1); + + list($x2,$y2) = $this->contourCoord[$c][$i++][1]; + $x2t = $xscale->Translate($x2); + $y2t = $yscale->Translate($y2); + + $img->Line($x1t,$y1t,$x2t,$y2t); + } + + } + } + +} + +// EOF +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_date.php b/ext/jpgraph-3.0.7/src/jpgraph_date.php index 6adc9e4..b830254 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_date.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_date.php @@ -1,499 +1,499 @@ -type=$aType; - $this->scale=array($aMin,$aMax); - $this->world_size=$aMax-$aMin; - $this->ticks = new LinearTicks(); - $this->intscale=true; - } - - - //------------------------------------------------------------------------------------------ - // Utility Function AdjDate() - // Description: Will round a given time stamp to an even year, month or day - // argument. - //------------------------------------------------------------------------------------------ - - function AdjDate($aTime,$aRound=0,$aYearType=false,$aMonthType=false,$aDayType=false) { - $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); - $h=0;$i=0;$s=0; - if( $aYearType !== false ) { - $yearAdj = array(0=>1, 1=>2, 2=>5); - if( $aRound == 0 ) { - $y = floor($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; - } - else { - ++$y; - $y = ceil($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; - } - $m=1;$d=1; - } - elseif( $aMonthType !== false ) { - $monthAdj = array(0=>1, 1=>6); - if( $aRound == 0 ) { - $m = floor($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; - $d=1; - } - else { - ++$m; - $m = ceil($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; - $d=1; - } - } - elseif( $aDayType !== false ) { - if( $aDayType == 0 ) { - if( $aRound == 1 ) { - //++$d; - $h=23;$i=59;$s=59; - } - } - else { - // Adjust to an even week boundary. - $w = (int)date('w',$aTime); // Day of week 0=Sun, 6=Sat - if( true ) { // Adjust to start on Mon - if( $w==0 ) $w=6; - else --$w; - } - if( $aRound == 0 ) { - $d -= $w; - } - else { - $d += (7-$w); - $h=23;$i=59;$s=59; - } - } - } - return mktime($h,$i,$s,$m,$d,$y); - - } - - //------------------------------------------------------------------------------------------ - // Wrapper for AdjDate that will round a timestamp to an even date rounding - // it downwards. - //------------------------------------------------------------------------------------------ - function AdjStartDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { - return $this->AdjDate($aTime,0,$aYearType,$aMonthType,$aDayType); - } - - //------------------------------------------------------------------------------------------ - // Wrapper for AdjDate that will round a timestamp to an even date rounding - // it upwards - //------------------------------------------------------------------------------------------ - function AdjEndDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { - return $this->AdjDate($aTime,1,$aYearType,$aMonthType,$aDayType); - } - - //------------------------------------------------------------------------------------------ - // Utility Function AdjTime() - // Description: Will round a given time stamp to an even time according to - // argument. - //------------------------------------------------------------------------------------------ - - function AdjTime($aTime,$aRound=0,$aHourType=false,$aMinType=false,$aSecType=false) { - $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); - $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); $s = (int)date('s',$aTime); - if( $aHourType !== false ) { - $aHourType %= 6; - $hourAdj = array(0=>1, 1=>2, 2=>3, 3=>4, 4=>6, 5=>12); - if( $aRound == 0 ) - $h = floor($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; - else { - if( ($h % $hourAdj[$aHourType]==0) && ($i > 0 || $s > 0) ) { - $h++; - } - $h = ceil($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; - if( $h >= 24 ) { - $aTime += 86400; - $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); - $h -= 24; - } - } - $i=0;$s=0; - } - elseif( $aMinType !== false ) { - $aMinType %= 5; - $minAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); - if( $aRound == 0 ) { - $i = floor($i/$minAdj[$aMinType])*$minAdj[$aMinType]; - } - else { - if( ($i % $minAdj[$aMinType]==0) && $s > 0 ) { - $i++; - } - $i = ceil($i/$minAdj[$aMinType])*$minAdj[$aMinType]; - if( $i >= 60) { - $aTime += 3600; - $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); - $h = (int)date('H',$aTime); $i = 0; - } - } - $s=0; - } - elseif( $aSecType !== false ) { - $aSecType %= 5; - $secAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); - if( $aRound == 0 ) { - $s = floor($s/$secAdj[$aSecType])*$secAdj[$aSecType]; - } - else { - $s = ceil($s/$secAdj[$aSecType]*1.0)*$secAdj[$aSecType]; - if( $s >= 60) { - $s=0; - $aTime += 60; - $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); - $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); - } - } - } - return mktime($h,$i,$s,$m,$d,$y); - } - - //------------------------------------------------------------------------------------------ - // Wrapper for AdjTime that will round a timestamp to an even time rounding - // it downwards. - // Example: AdjStartTime(mktime(18,27,13,2,22,2005),false,2) => 18:20 - //------------------------------------------------------------------------------------------ - function AdjStartTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { - return $this->AdjTime($aTime,0,$aHourType,$aMinType,$aSecType); - } - - //------------------------------------------------------------------------------------------ - // Wrapper for AdjTime that will round a timestamp to an even time rounding - // it upwards - // Example: AdjEndTime(mktime(18,27,13,2,22,2005),false,2) => 18:30 - //------------------------------------------------------------------------------------------ - function AdjEndTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { - return $this->AdjTime($aTime,1,$aHourType,$aMinType,$aSecType); - } - - //------------------------------------------------------------------------------------------ - // DateAutoScale - // Autoscale a date axis given start and end time - // Returns an array ($start,$end,$major,$minor,$format) - //------------------------------------------------------------------------------------------ - function DoDateAutoScale($aStartTime,$aEndTime,$aDensity=0,$aAdjust=true) { - // Format of array - // array ( Decision point, array( array( Major-scale-step-array ), - // array( Minor-scale-step-array ), - // array( 0=date-adjust, 1=time-adjust, adjustment-alignment) ) - // - $scalePoints = - array( - /* Intervall larger than 10 years */ - SECPERYEAR*10,array(array(SECPERYEAR*5,SECPERYEAR*2), - array(SECPERYEAR), - array(0,YEARADJ_1, 0,YEARADJ_1) ), - - /* Intervall larger than 2 years */ - SECPERYEAR*2,array(array(SECPERYEAR),array(SECPERYEAR), - array(0,YEARADJ_1) ), - - /* Intervall larger than 90 days (approx 3 month) */ - SECPERDAY*90,array(array(SECPERDAY*30,SECPERDAY*14,SECPERDAY*7,SECPERDAY), - array(SECPERDAY*5,SECPERDAY*7,SECPERDAY,SECPERDAY), - array(0,MONTHADJ_1, 0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1)), - - /* Intervall larger than 30 days (approx 1 month) */ - SECPERDAY*30,array(array(SECPERDAY*14,SECPERDAY*7,SECPERDAY*2, SECPERDAY), - array(SECPERDAY,SECPERDAY,SECPERDAY,SECPERDAY), - array(0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1, 0,DAYADJ_1)), - - /* Intervall larger than 7 days */ - SECPERDAY*7,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2), - array(SECPERHOUR*6,SECPERHOUR*3,SECPERHOUR,SECPERHOUR), - array(0,DAYADJ_1, 1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1)), - - /* Intervall larger than 1 day */ - SECPERDAY,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR), - array(SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR,SECPERHOUR,SECPERHOUR), - array(1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1, 1,HOURADJ_1)), - - /* Intervall larger than 12 hours */ - SECPERHOUR*12,array(array(SECPERHOUR*2,SECPERHOUR,SECPERMIN*30,900,600), - array(1800,1800,900,300,300), - array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), - - /* Intervall larger than 2 hours */ - SECPERHOUR*2,array(array(SECPERHOUR,SECPERMIN*30,900,600,300), - array(1800,900,300,120,60), - array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), - - /* Intervall larger than 1 hours */ - SECPERHOUR,array(array(SECPERMIN*30,900,600,300),array(900,300,120,60), - array(1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), - - /* Intervall larger than 30 min */ - SECPERMIN*30,array(array(SECPERMIN*15,SECPERMIN*10,SECPERMIN*5,SECPERMIN), - array(300,300,60,10), - array(1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5, 1,MINADJ_1)), - - /* Intervall larger than 1 min */ - SECPERMIN,array(array(SECPERMIN,15,10,5), - array(15,5,2,1), - array(1,MINADJ_1, 1,SECADJ_15, 1,SECADJ_10, 1,SECADJ_5)), - - /* Intervall larger than 10 sec */ - 10,array(array(5,2), - array(1,1), - array(1,SECADJ_5, 1,SECADJ_1)), - - /* Intervall larger than 1 sec */ - 1,array(array(1), - array(1), - array(1,SECADJ_1)), - ); - - $ns = count($scalePoints); - // Establish major and minor scale units for the date scale - $diff = $aEndTime - $aStartTime; - if( $diff < 1 ) return false; - $done=false; - $i=0; - while( ! $done ) { - if( $diff > $scalePoints[2*$i] ) { - // Get major and minor scale for this intervall - $scaleSteps = $scalePoints[2*$i+1]; - $major = $scaleSteps[0][min($aDensity,count($scaleSteps[0])-1)]; - // Try to find out which minor step looks best - $minor = $scaleSteps[1][min($aDensity,count($scaleSteps[1])-1)]; - if( $aAdjust ) { - // Find out how we should align the start and end timestamps - $idx = 2*min($aDensity,floor(count($scaleSteps[2])/2)-1); - if( $scaleSteps[2][$idx] === 0 ) { - // Use date adjustment - $adj = $scaleSteps[2][$idx+1]; - if( $adj >= 30 ) { - $start = $this->AdjStartDate($aStartTime,$adj-30); - $end = $this->AdjEndDate($aEndTime,$adj-30); - } - elseif( $adj >= 20 ) { - $start = $this->AdjStartDate($aStartTime,false,$adj-20); - $end = $this->AdjEndDate($aEndTime,false,$adj-20); - } - else { - $start = $this->AdjStartDate($aStartTime,false,false,$adj); - $end = $this->AdjEndDate($aEndTime,false,false,$adj); - // We add 1 second for date adjustment to make sure we end on 00:00 the following day - // This makes the final major tick be srawn when we step day-by-day instead of ending - // on xx:59:59 which would not draw the final major tick - $end++; - } - } - else { - // Use time adjustment - $adj = $scaleSteps[2][$idx+1]; - if( $adj >= 30 ) { - $start = $this->AdjStartTime($aStartTime,$adj-30); - $end = $this->AdjEndTime($aEndTime,$adj-30); - } - elseif( $adj >= 20 ) { - $start = $this->AdjStartTime($aStartTime,false,$adj-20); - $end = $this->AdjEndTime($aEndTime,false,$adj-20); - } - else { - $start = $this->AdjStartTime($aStartTime,false,false,$adj); - $end = $this->AdjEndTime($aEndTime,false,false,$adj); - } - } - } - // If the overall date span is larger than 1 day ten we show date - $format = ''; - if( ($end-$start) > SECPERDAY ) { - $format = 'Y-m-d '; - } - // If the major step is less than 1 day we need to whow hours + min - if( $major < SECPERDAY ) { - $format .= 'H:i'; - } - // If the major step is less than 1 min we need to show sec - if( $major < 60 ) { - $format .= ':s'; - } - $done=true; - } - ++$i; - } - return array($start,$end,$major,$minor,$format); - } - - // Overrides the automatic determined date format. Must be a valid date() format string - function SetDateFormat($aFormat) { - $this->date_format = $aFormat; - $this->ticks->SetLabelDateFormat($this->date_format); - } - - function AdjustForDST($aFlg=true) { - $this->ticks->AdjustForDST($aFlg); - } - - - function SetDateAlign($aStartAlign,$aEndAlign=false) { - if( $aEndAlign === false ) { - $aEndAlign=$aStartAlign; - } - $this->iStartAlign = $aStartAlign; - $this->iEndAlign = $aEndAlign; - } - - function SetTimeAlign($aStartAlign,$aEndAlign=false) { - if( $aEndAlign === false ) { - $aEndAlign=$aStartAlign; - } - $this->iStartTimeAlign = $aStartAlign; - $this->iEndTimeAlign = $aEndAlign; - } - - - function AutoScale($img,$aStartTime,$aEndTime,$aNumSteps,$_adummy=false) { - // We need to have one dummy argument to make the signature of AutoScale() - // identical to LinearScale::AutoScale - if( $aStartTime == $aEndTime ) { - // Special case when we only have one data point. - // Create a small artifical intervall to do the autoscaling - $aStartTime -= 10; - $aEndTime += 10; - } - $done=false; - $i=0; - while( ! $done && $i < 5) { - list($adjstart,$adjend,$maj,$min,$format) = $this->DoDateAutoScale($aStartTime,$aEndTime,$i); - $n = floor(($adjend-$adjstart)/$maj); - if( $n * 1.7 > $aNumSteps ) { - $done=true; - } - $i++; - } - - /* - if( 0 ) { // DEBUG - echo " Start =".date("Y-m-d H:i:s",$aStartTime)."
      "; - echo " End =".date("Y-m-d H:i:s",$aEndTime)."
      "; - echo "Adj Start =".date("Y-m-d H:i:s",$adjstart)."
      "; - echo "Adj End =".date("Y-m-d H:i:s",$adjend)."

      "; - echo "Major = $maj s, ".floor($maj/60)."min, ".floor($maj/3600)."h, ".floor($maj/86400)."day
      "; - echo "Min = $min s, ".floor($min/60)."min, ".floor($min/3600)."h, ".floor($min/86400)."day
      "; - echo "Format=$format

      "; - } - */ - - if( $this->iStartTimeAlign !== false && $this->iStartAlign !== false ) { - JpGraphError::RaiseL(3001); - //('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both'); - } - - if( $this->iStartTimeAlign !== false ) { - if( $this->iStartTimeAlign >= 30 ) { - $adjstart = $this->AdjStartTime($aStartTime,$this->iStartTimeAlign-30); - } - elseif( $this->iStartTimeAlign >= 20 ) { - $adjstart = $this->AdjStartTime($aStartTime,false,$this->iStartTimeAlign-20); - } - else { - $adjstart = $this->AdjStartTime($aStartTime,false,false,$this->iStartTimeAlign); - } - } - if( $this->iEndTimeAlign !== false ) { - if( $this->iEndTimeAlign >= 30 ) { - $adjend = $this->AdjEndTime($aEndTime,$this->iEndTimeAlign-30); - } - elseif( $this->iEndTimeAlign >= 20 ) { - $adjend = $this->AdjEndTime($aEndTime,false,$this->iEndTimeAlign-20); - } - else { - $adjend = $this->AdjEndTime($aEndTime,false,false,$this->iEndTimeAlign); - } - } - - - - if( $this->iStartAlign !== false ) { - if( $this->iStartAlign >= 30 ) { - $adjstart = $this->AdjStartDate($aStartTime,$this->iStartAlign-30); - } - elseif( $this->iStartAlign >= 20 ) { - $adjstart = $this->AdjStartDate($aStartTime,false,$this->iStartAlign-20); - } - else { - $adjstart = $this->AdjStartDate($aStartTime,false,false,$this->iStartAlign); - } - } - if( $this->iEndAlign !== false ) { - if( $this->iEndAlign >= 30 ) { - $adjend = $this->AdjEndDate($aEndTime,$this->iEndAlign-30); - } - elseif( $this->iEndAlign >= 20 ) { - $adjend = $this->AdjEndDate($aEndTime,false,$this->iEndAlign-20); - } - else { - $adjend = $this->AdjEndDate($aEndTime,false,false,$this->iEndAlign); - } - } - $this->Update($img,$adjstart,$adjend); - if( ! $this->ticks->IsSpecified() ) - $this->ticks->Set($maj,$min); - if( $this->date_format == '' ) - $this->ticks->SetLabelDateFormat($format); - else - $this->ticks->SetLabelDateFormat($this->date_format); - } -} - - -?> +type=$aType; + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->ticks = new LinearTicks(); + $this->intscale=true; + } + + + //------------------------------------------------------------------------------------------ + // Utility Function AdjDate() + // Description: Will round a given time stamp to an even year, month or day + // argument. + //------------------------------------------------------------------------------------------ + + function AdjDate($aTime,$aRound=0,$aYearType=false,$aMonthType=false,$aDayType=false) { + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h=0;$i=0;$s=0; + if( $aYearType !== false ) { + $yearAdj = array(0=>1, 1=>2, 2=>5); + if( $aRound == 0 ) { + $y = floor($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; + } + else { + ++$y; + $y = ceil($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; + } + $m=1;$d=1; + } + elseif( $aMonthType !== false ) { + $monthAdj = array(0=>1, 1=>6); + if( $aRound == 0 ) { + $m = floor($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; + $d=1; + } + else { + ++$m; + $m = ceil($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; + $d=1; + } + } + elseif( $aDayType !== false ) { + if( $aDayType == 0 ) { + if( $aRound == 1 ) { + //++$d; + $h=23;$i=59;$s=59; + } + } + else { + // Adjust to an even week boundary. + $w = (int)date('w',$aTime); // Day of week 0=Sun, 6=Sat + if( true ) { // Adjust to start on Mon + if( $w==0 ) $w=6; + else --$w; + } + if( $aRound == 0 ) { + $d -= $w; + } + else { + $d += (7-$w); + $h=23;$i=59;$s=59; + } + } + } + return mktime($h,$i,$s,$m,$d,$y); + + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjDate that will round a timestamp to an even date rounding + // it downwards. + //------------------------------------------------------------------------------------------ + function AdjStartDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { + return $this->AdjDate($aTime,0,$aYearType,$aMonthType,$aDayType); + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjDate that will round a timestamp to an even date rounding + // it upwards + //------------------------------------------------------------------------------------------ + function AdjEndDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { + return $this->AdjDate($aTime,1,$aYearType,$aMonthType,$aDayType); + } + + //------------------------------------------------------------------------------------------ + // Utility Function AdjTime() + // Description: Will round a given time stamp to an even time according to + // argument. + //------------------------------------------------------------------------------------------ + + function AdjTime($aTime,$aRound=0,$aHourType=false,$aMinType=false,$aSecType=false) { + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); $s = (int)date('s',$aTime); + if( $aHourType !== false ) { + $aHourType %= 6; + $hourAdj = array(0=>1, 1=>2, 2=>3, 3=>4, 4=>6, 5=>12); + if( $aRound == 0 ) + $h = floor($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; + else { + if( ($h % $hourAdj[$aHourType]==0) && ($i > 0 || $s > 0) ) { + $h++; + } + $h = ceil($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; + if( $h >= 24 ) { + $aTime += 86400; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h -= 24; + } + } + $i=0;$s=0; + } + elseif( $aMinType !== false ) { + $aMinType %= 5; + $minAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); + if( $aRound == 0 ) { + $i = floor($i/$minAdj[$aMinType])*$minAdj[$aMinType]; + } + else { + if( ($i % $minAdj[$aMinType]==0) && $s > 0 ) { + $i++; + } + $i = ceil($i/$minAdj[$aMinType])*$minAdj[$aMinType]; + if( $i >= 60) { + $aTime += 3600; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = 0; + } + } + $s=0; + } + elseif( $aSecType !== false ) { + $aSecType %= 5; + $secAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); + if( $aRound == 0 ) { + $s = floor($s/$secAdj[$aSecType])*$secAdj[$aSecType]; + } + else { + $s = ceil($s/$secAdj[$aSecType]*1.0)*$secAdj[$aSecType]; + if( $s >= 60) { + $s=0; + $aTime += 60; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); + } + } + } + return mktime($h,$i,$s,$m,$d,$y); + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjTime that will round a timestamp to an even time rounding + // it downwards. + // Example: AdjStartTime(mktime(18,27,13,2,22,2005),false,2) => 18:20 + //------------------------------------------------------------------------------------------ + function AdjStartTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { + return $this->AdjTime($aTime,0,$aHourType,$aMinType,$aSecType); + } + + //------------------------------------------------------------------------------------------ + // Wrapper for AdjTime that will round a timestamp to an even time rounding + // it upwards + // Example: AdjEndTime(mktime(18,27,13,2,22,2005),false,2) => 18:30 + //------------------------------------------------------------------------------------------ + function AdjEndTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { + return $this->AdjTime($aTime,1,$aHourType,$aMinType,$aSecType); + } + + //------------------------------------------------------------------------------------------ + // DateAutoScale + // Autoscale a date axis given start and end time + // Returns an array ($start,$end,$major,$minor,$format) + //------------------------------------------------------------------------------------------ + function DoDateAutoScale($aStartTime,$aEndTime,$aDensity=0,$aAdjust=true) { + // Format of array + // array ( Decision point, array( array( Major-scale-step-array ), + // array( Minor-scale-step-array ), + // array( 0=date-adjust, 1=time-adjust, adjustment-alignment) ) + // + $scalePoints = + array( + /* Intervall larger than 10 years */ + SECPERYEAR*10,array(array(SECPERYEAR*5,SECPERYEAR*2), + array(SECPERYEAR), + array(0,YEARADJ_1, 0,YEARADJ_1) ), + + /* Intervall larger than 2 years */ + SECPERYEAR*2,array(array(SECPERYEAR),array(SECPERYEAR), + array(0,YEARADJ_1) ), + + /* Intervall larger than 90 days (approx 3 month) */ + SECPERDAY*90,array(array(SECPERDAY*30,SECPERDAY*14,SECPERDAY*7,SECPERDAY), + array(SECPERDAY*5,SECPERDAY*7,SECPERDAY,SECPERDAY), + array(0,MONTHADJ_1, 0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1)), + + /* Intervall larger than 30 days (approx 1 month) */ + SECPERDAY*30,array(array(SECPERDAY*14,SECPERDAY*7,SECPERDAY*2, SECPERDAY), + array(SECPERDAY,SECPERDAY,SECPERDAY,SECPERDAY), + array(0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1, 0,DAYADJ_1)), + + /* Intervall larger than 7 days */ + SECPERDAY*7,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2), + array(SECPERHOUR*6,SECPERHOUR*3,SECPERHOUR,SECPERHOUR), + array(0,DAYADJ_1, 1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1)), + + /* Intervall larger than 1 day */ + SECPERDAY,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR), + array(SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR,SECPERHOUR,SECPERHOUR), + array(1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1, 1,HOURADJ_1)), + + /* Intervall larger than 12 hours */ + SECPERHOUR*12,array(array(SECPERHOUR*2,SECPERHOUR,SECPERMIN*30,900,600), + array(1800,1800,900,300,300), + array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 2 hours */ + SECPERHOUR*2,array(array(SECPERHOUR,SECPERMIN*30,900,600,300), + array(1800,900,300,120,60), + array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 1 hours */ + SECPERHOUR,array(array(SECPERMIN*30,900,600,300),array(900,300,120,60), + array(1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 30 min */ + SECPERMIN*30,array(array(SECPERMIN*15,SECPERMIN*10,SECPERMIN*5,SECPERMIN), + array(300,300,60,10), + array(1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5, 1,MINADJ_1)), + + /* Intervall larger than 1 min */ + SECPERMIN,array(array(SECPERMIN,15,10,5), + array(15,5,2,1), + array(1,MINADJ_1, 1,SECADJ_15, 1,SECADJ_10, 1,SECADJ_5)), + + /* Intervall larger than 10 sec */ + 10,array(array(5,2), + array(1,1), + array(1,SECADJ_5, 1,SECADJ_1)), + + /* Intervall larger than 1 sec */ + 1,array(array(1), + array(1), + array(1,SECADJ_1)), + ); + + $ns = count($scalePoints); + // Establish major and minor scale units for the date scale + $diff = $aEndTime - $aStartTime; + if( $diff < 1 ) return false; + $done=false; + $i=0; + while( ! $done ) { + if( $diff > $scalePoints[2*$i] ) { + // Get major and minor scale for this intervall + $scaleSteps = $scalePoints[2*$i+1]; + $major = $scaleSteps[0][min($aDensity,count($scaleSteps[0])-1)]; + // Try to find out which minor step looks best + $minor = $scaleSteps[1][min($aDensity,count($scaleSteps[1])-1)]; + if( $aAdjust ) { + // Find out how we should align the start and end timestamps + $idx = 2*min($aDensity,floor(count($scaleSteps[2])/2)-1); + if( $scaleSteps[2][$idx] === 0 ) { + // Use date adjustment + $adj = $scaleSteps[2][$idx+1]; + if( $adj >= 30 ) { + $start = $this->AdjStartDate($aStartTime,$adj-30); + $end = $this->AdjEndDate($aEndTime,$adj-30); + } + elseif( $adj >= 20 ) { + $start = $this->AdjStartDate($aStartTime,false,$adj-20); + $end = $this->AdjEndDate($aEndTime,false,$adj-20); + } + else { + $start = $this->AdjStartDate($aStartTime,false,false,$adj); + $end = $this->AdjEndDate($aEndTime,false,false,$adj); + // We add 1 second for date adjustment to make sure we end on 00:00 the following day + // This makes the final major tick be srawn when we step day-by-day instead of ending + // on xx:59:59 which would not draw the final major tick + $end++; + } + } + else { + // Use time adjustment + $adj = $scaleSteps[2][$idx+1]; + if( $adj >= 30 ) { + $start = $this->AdjStartTime($aStartTime,$adj-30); + $end = $this->AdjEndTime($aEndTime,$adj-30); + } + elseif( $adj >= 20 ) { + $start = $this->AdjStartTime($aStartTime,false,$adj-20); + $end = $this->AdjEndTime($aEndTime,false,$adj-20); + } + else { + $start = $this->AdjStartTime($aStartTime,false,false,$adj); + $end = $this->AdjEndTime($aEndTime,false,false,$adj); + } + } + } + // If the overall date span is larger than 1 day ten we show date + $format = ''; + if( ($end-$start) > SECPERDAY ) { + $format = 'Y-m-d '; + } + // If the major step is less than 1 day we need to whow hours + min + if( $major < SECPERDAY ) { + $format .= 'H:i'; + } + // If the major step is less than 1 min we need to show sec + if( $major < 60 ) { + $format .= ':s'; + } + $done=true; + } + ++$i; + } + return array($start,$end,$major,$minor,$format); + } + + // Overrides the automatic determined date format. Must be a valid date() format string + function SetDateFormat($aFormat) { + $this->date_format = $aFormat; + $this->ticks->SetLabelDateFormat($this->date_format); + } + + function AdjustForDST($aFlg=true) { + $this->ticks->AdjustForDST($aFlg); + } + + + function SetDateAlign($aStartAlign,$aEndAlign=false) { + if( $aEndAlign === false ) { + $aEndAlign=$aStartAlign; + } + $this->iStartAlign = $aStartAlign; + $this->iEndAlign = $aEndAlign; + } + + function SetTimeAlign($aStartAlign,$aEndAlign=false) { + if( $aEndAlign === false ) { + $aEndAlign=$aStartAlign; + } + $this->iStartTimeAlign = $aStartAlign; + $this->iEndTimeAlign = $aEndAlign; + } + + + function AutoScale($img,$aStartTime,$aEndTime,$aNumSteps,$_adummy=false) { + // We need to have one dummy argument to make the signature of AutoScale() + // identical to LinearScale::AutoScale + if( $aStartTime == $aEndTime ) { + // Special case when we only have one data point. + // Create a small artifical intervall to do the autoscaling + $aStartTime -= 10; + $aEndTime += 10; + } + $done=false; + $i=0; + while( ! $done && $i < 5) { + list($adjstart,$adjend,$maj,$min,$format) = $this->DoDateAutoScale($aStartTime,$aEndTime,$i); + $n = floor(($adjend-$adjstart)/$maj); + if( $n * 1.7 > $aNumSteps ) { + $done=true; + } + $i++; + } + + /* + if( 0 ) { // DEBUG + echo " Start =".date("Y-m-d H:i:s",$aStartTime)."
      "; + echo " End =".date("Y-m-d H:i:s",$aEndTime)."
      "; + echo "Adj Start =".date("Y-m-d H:i:s",$adjstart)."
      "; + echo "Adj End =".date("Y-m-d H:i:s",$adjend)."

      "; + echo "Major = $maj s, ".floor($maj/60)."min, ".floor($maj/3600)."h, ".floor($maj/86400)."day
      "; + echo "Min = $min s, ".floor($min/60)."min, ".floor($min/3600)."h, ".floor($min/86400)."day
      "; + echo "Format=$format

      "; + } + */ + + if( $this->iStartTimeAlign !== false && $this->iStartAlign !== false ) { + JpGraphError::RaiseL(3001); + //('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both'); + } + + if( $this->iStartTimeAlign !== false ) { + if( $this->iStartTimeAlign >= 30 ) { + $adjstart = $this->AdjStartTime($aStartTime,$this->iStartTimeAlign-30); + } + elseif( $this->iStartTimeAlign >= 20 ) { + $adjstart = $this->AdjStartTime($aStartTime,false,$this->iStartTimeAlign-20); + } + else { + $adjstart = $this->AdjStartTime($aStartTime,false,false,$this->iStartTimeAlign); + } + } + if( $this->iEndTimeAlign !== false ) { + if( $this->iEndTimeAlign >= 30 ) { + $adjend = $this->AdjEndTime($aEndTime,$this->iEndTimeAlign-30); + } + elseif( $this->iEndTimeAlign >= 20 ) { + $adjend = $this->AdjEndTime($aEndTime,false,$this->iEndTimeAlign-20); + } + else { + $adjend = $this->AdjEndTime($aEndTime,false,false,$this->iEndTimeAlign); + } + } + + + + if( $this->iStartAlign !== false ) { + if( $this->iStartAlign >= 30 ) { + $adjstart = $this->AdjStartDate($aStartTime,$this->iStartAlign-30); + } + elseif( $this->iStartAlign >= 20 ) { + $adjstart = $this->AdjStartDate($aStartTime,false,$this->iStartAlign-20); + } + else { + $adjstart = $this->AdjStartDate($aStartTime,false,false,$this->iStartAlign); + } + } + if( $this->iEndAlign !== false ) { + if( $this->iEndAlign >= 30 ) { + $adjend = $this->AdjEndDate($aEndTime,$this->iEndAlign-30); + } + elseif( $this->iEndAlign >= 20 ) { + $adjend = $this->AdjEndDate($aEndTime,false,$this->iEndAlign-20); + } + else { + $adjend = $this->AdjEndDate($aEndTime,false,false,$this->iEndAlign); + } + } + $this->Update($img,$adjstart,$adjend); + if( ! $this->ticks->IsSpecified() ) + $this->ticks->Set($maj,$min); + if( $this->date_format == '' ) + $this->ticks->SetLabelDateFormat($format); + else + $this->ticks->SetLabelDateFormat($this->date_format); + } +} + + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_errhandler.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_errhandler.inc.php index 1ed4a9c..81547ca 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_errhandler.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_errhandler.inc.php @@ -1,368 +1,368 @@ -lt = $_jpg_messages; - } - - function Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { - GLOBAL $__jpg_err_locale; - if( !isset($this->lt[$errnbr]) ) { - return 'Internal error: The specified error message ('.$errnbr.') does not exist in the chosen locale ('.$__jpg_err_locale.')'; - } - $ea = $this->lt[$errnbr]; - $j=0; - if( $a1 !== null ) { - $argv[$j++] = $a1; - if( $a2 !== null ) { - $argv[$j++] = $a2; - if( $a3 !== null ) { - $argv[$j++] = $a3; - if( $a4 !== null ) { - $argv[$j++] = $a4; - if( $a5 !== null ) { - $argv[$j++] = $a5; - } - } - } - } - } - $numargs = $j; - if( $ea[1] != $numargs ) { - // Error message argument count do not match. - // Just return the error message without arguments. - return $ea[0]; - } - switch( $numargs ) { - case 1: - $msg = sprintf($ea[0],$argv[0]); - break; - case 2: - $msg = sprintf($ea[0],$argv[0],$argv[1]); - break; - case 3: - $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2]); - break; - case 4: - $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]); - break; - case 5: - $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]); - break; - case 0: - default: - $msg = sprintf($ea[0]); - break; - } - return $msg; - } -} - -// -// A wrapper class that is used to access the specified error object -// (to hide the global error parameter and avoid having a GLOBAL directive -// in all methods. -// -class JpGraphError { - private static $__iImgFlg = true; - private static $__iLogFile = ''; - private static $__iTitle = 'JpGraph Error: '; - public static function Raise($aMsg,$aHalt=true){ - throw new JpGraphException($aMsg); - } - public static function SetErrLocale($aLoc) { - GLOBAL $__jpg_err_locale ; - $__jpg_err_locale = $aLoc; - } - public static function RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { - throw new JpGraphExceptionL($errnbr,$a1,$a2,$a3,$a4,$a5); - } - public static function SetImageFlag($aFlg=true) { - self::$__iImgFlg = $aFlg; - } - public static function GetImageFlag() { - return self::$__iImgFlg; - } - public static function SetLogFile($aFile) { - self::$__iLogFile = $aFile; - } - public static function GetLogFile() { - return self::$__iLogFile; - } - public static function SetTitle($aTitle) { - self::$__iTitle = $aTitle; - } - public static function GetTitle() { - return self::$__iTitle; - } -} - -class JpGraphException extends Exception { - // Redefine the exception so message isn't optional - public function __construct($message, $code = 0) { - // make sure everything is assigned properly - parent::__construct($message, $code); - } - // custom string representation of object - public function _toString() { - return __CLASS__ . ": [{$this->code}]: {$this->message} at " . basename($this->getFile()) . ":" . $this->getLine() . "\n" . $this->getTraceAsString() . "\n"; - } - // custom representation of error as an image - public function Stroke() { - if( JpGraphError::GetImageFlag() ) { - $errobj = new JpGraphErrObjectImg(); - $errobj->SetTitle(JpGraphError::GetTitle()); - } - else { - $errobj = new JpGraphErrObject(); - $errobj->SetTitle(JpGraphError::GetTitle()); - $errobj->SetStrokeDest(JpGraphError::GetLogFile()); - } - $errobj->Raise($this->getMessage()); - } - static public function defaultHandler(Exception $exception) { - global $__jpg_OldHandler; - if( $exception instanceof JpGraphException ) { - $exception->Stroke(); - } - else { - // Restore old handler - if( $__jpg_OldHandler !== NULL ) { - set_exception_handler($__jpg_OldHandler); - } - throw $exception; - } - } -} - -class JpGraphExceptionL extends JpGraphException { - // Redefine the exception so message isn't optional - public function __construct($errcode,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { - // make sure everything is assigned properly - $errtxt = new ErrMsgText(); - JpGraphError::SetTitle('JpGraph Error: '.$errcode); - parent::__construct($errtxt->Get($errcode,$a1,$a2,$a3,$a4,$a5), 0); - } -} - -// Setup the default handler -global $__jpg_OldHandler; -$__jpg_OldHandler = set_exception_handler(array('JpGraphException','defaultHandler')); - -// -// First of all set up a default error handler -// - -//============================================================= -// The default trivial text error handler. -//============================================================= -class JpGraphErrObject { - - protected $iTitle = "JpGraph error: "; - protected $iDest = false; - - - function __construct() { - // Empty. Reserved for future use - } - - function SetTitle($aTitle) { - $this->iTitle = $aTitle; - } - - function SetStrokeDest($aDest) { - $this->iDest = $aDest; - } - - // If aHalt is true then execution can't continue. Typical used for fatal errors - function Raise($aMsg,$aHalt=false) { - if( $this->iDest != '' ) { - if( $this->iDest == 'syslog' ) { - error_log($this->iTitle.$aMsg); - } - else { - $str = '['.date('r').'] '.$this->iTitle.$aMsg."\n"; - $f = @fopen($this->iDest,'a'); - if( $f ) { - @fwrite($f,$str); - @fclose($f); - } - } - } - else { - $aMsg = $this->iTitle.$aMsg; - // Check SAPI and if we are called from the command line - // send the error to STDERR instead - if( PHP_SAPI == 'cli' ) { - fwrite(STDERR,$aMsg); - } - else { - echo $aMsg; - } - } - if( $aHalt ) - exit(1); - } -} - -//============================================================== -// An image based error handler -//============================================================== -class JpGraphErrObjectImg extends JpGraphErrObject { - - function __construct() { - parent::__construct(); - // Empty. Reserved for future use - } - - function Raise($aMsg,$aHalt=true) { - $img_iconerror = - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'. - 'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. - 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'. - 'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. - 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. - 'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'. - '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'. - 'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'. - 'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'. - 'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'. - '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'. - 'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'. - 'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'. - 'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'. - 'qL72fwAAAABJRU5ErkJggg==' ; - - - if( function_exists("imagetypes") ) { - $supported = imagetypes(); - } else { - $supported = 0; - } - - if( !function_exists('imagecreatefromstring') ) { - $supported = 0; - } - - if( ob_get_length() || headers_sent() || !($supported & IMG_PNG) ) { - // Special case for headers already sent or that the installation doesn't support - // the PNG format (which the error icon is encoded in). - // Dont return an image since it can't be displayed - die($this->iTitle.' '.$aMsg); - } - - $aMsg = wordwrap($aMsg,55); - $lines = substr_count($aMsg,"\n"); - - // Create the error icon GD - $erricon = Image::CreateFromString(base64_decode($img_iconerror)); - - // Create an image that contains the error text. - $w=400; - $h=100 + 15*max(0,$lines-3); - - $img = new Image($w,$h); - - - // Drop shadow - $img->SetColor("gray"); - $img->FilledRectangle(5,5,$w-1,$h-1,10); - $img->SetColor("gray:0.7"); - $img->FilledRectangle(5,5,$w-3,$h-3,10); - - // Window background - $img->SetColor("lightblue"); - $img->FilledRectangle(1,1,$w-5,$h-5); - $img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40); - - // Window border - $img->SetColor("black"); - $img->Rectangle(1,1,$w-5,$h-5); - $img->Rectangle(0,0,$w-4,$h-4); - - // Window top row - $img->SetColor("darkred"); - for($y=3; $y < 18; $y += 2 ) - $img->Line(1,$y,$w-6,$y); - - // "White shadow" - $img->SetColor("white"); - - // Left window edge - $img->Line(2,2,2,$h-5); - $img->Line(2,2,$w-6,2); - - // "Gray button shadow" - $img->SetColor("darkgray"); - - // Gray window shadow - $img->Line(2,$h-6,$w-5,$h-6); - $img->Line(3,$h-7,$w-5,$h-7); - - // Window title - $m = floor($w/2-5); - $l = 110; - $img->SetColor("lightgray:1.3"); - $img->FilledRectangle($m-$l,2,$m+$l,16); - - // Stroke text - $img->SetColor("darkred"); - $img->SetFont(FF_FONT2,FS_BOLD); - $img->StrokeText($m-90,15,$this->iTitle); - $img->SetColor("black"); - $img->SetFont(FF_FONT1,FS_NORMAL); - $txt = new Text($aMsg,52,25); - $txt->Align("left","top"); - $txt->Stroke($img); - if ($this->iDest) { - $img->Stream($this->iDest); - } else { - $img->Headers(); - $img->Stream(); - } - if( $aHalt ) - die(); - } -} - - - -if( ! USE_IMAGE_ERROR_HANDLER ) { - JpGraphError::SetImageFlag(false); -} -?> +lt = $_jpg_messages; + } + + function Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { + GLOBAL $__jpg_err_locale; + if( !isset($this->lt[$errnbr]) ) { + return 'Internal error: The specified error message ('.$errnbr.') does not exist in the chosen locale ('.$__jpg_err_locale.')'; + } + $ea = $this->lt[$errnbr]; + $j=0; + if( $a1 !== null ) { + $argv[$j++] = $a1; + if( $a2 !== null ) { + $argv[$j++] = $a2; + if( $a3 !== null ) { + $argv[$j++] = $a3; + if( $a4 !== null ) { + $argv[$j++] = $a4; + if( $a5 !== null ) { + $argv[$j++] = $a5; + } + } + } + } + } + $numargs = $j; + if( $ea[1] != $numargs ) { + // Error message argument count do not match. + // Just return the error message without arguments. + return $ea[0]; + } + switch( $numargs ) { + case 1: + $msg = sprintf($ea[0],$argv[0]); + break; + case 2: + $msg = sprintf($ea[0],$argv[0],$argv[1]); + break; + case 3: + $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2]); + break; + case 4: + $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]); + break; + case 5: + $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]); + break; + case 0: + default: + $msg = sprintf($ea[0]); + break; + } + return $msg; + } +} + +// +// A wrapper class that is used to access the specified error object +// (to hide the global error parameter and avoid having a GLOBAL directive +// in all methods. +// +class JpGraphError { + private static $__iImgFlg = true; + private static $__iLogFile = ''; + private static $__iTitle = 'JpGraph Error: '; + public static function Raise($aMsg,$aHalt=true){ + throw new JpGraphException($aMsg); + } + public static function SetErrLocale($aLoc) { + GLOBAL $__jpg_err_locale ; + $__jpg_err_locale = $aLoc; + } + public static function RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { + throw new JpGraphExceptionL($errnbr,$a1,$a2,$a3,$a4,$a5); + } + public static function SetImageFlag($aFlg=true) { + self::$__iImgFlg = $aFlg; + } + public static function GetImageFlag() { + return self::$__iImgFlg; + } + public static function SetLogFile($aFile) { + self::$__iLogFile = $aFile; + } + public static function GetLogFile() { + return self::$__iLogFile; + } + public static function SetTitle($aTitle) { + self::$__iTitle = $aTitle; + } + public static function GetTitle() { + return self::$__iTitle; + } +} + +class JpGraphException extends Exception { + // Redefine the exception so message isn't optional + public function __construct($message, $code = 0) { + // make sure everything is assigned properly + parent::__construct($message, $code); + } + // custom string representation of object + public function _toString() { + return __CLASS__ . ": [{$this->code}]: {$this->message} at " . basename($this->getFile()) . ":" . $this->getLine() . "\n" . $this->getTraceAsString() . "\n"; + } + // custom representation of error as an image + public function Stroke() { + if( JpGraphError::GetImageFlag() ) { + $errobj = new JpGraphErrObjectImg(); + $errobj->SetTitle(JpGraphError::GetTitle()); + } + else { + $errobj = new JpGraphErrObject(); + $errobj->SetTitle(JpGraphError::GetTitle()); + $errobj->SetStrokeDest(JpGraphError::GetLogFile()); + } + $errobj->Raise($this->getMessage()); + } + static public function defaultHandler(Exception $exception) { + global $__jpg_OldHandler; + if( $exception instanceof JpGraphException ) { + $exception->Stroke(); + } + else { + // Restore old handler + if( $__jpg_OldHandler !== NULL ) { + set_exception_handler($__jpg_OldHandler); + } + throw $exception; + } + } +} + +class JpGraphExceptionL extends JpGraphException { + // Redefine the exception so message isn't optional + public function __construct($errcode,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { + // make sure everything is assigned properly + $errtxt = new ErrMsgText(); + JpGraphError::SetTitle('JpGraph Error: '.$errcode); + parent::__construct($errtxt->Get($errcode,$a1,$a2,$a3,$a4,$a5), 0); + } +} + +// Setup the default handler +global $__jpg_OldHandler; +$__jpg_OldHandler = set_exception_handler(array('JpGraphException','defaultHandler')); + +// +// First of all set up a default error handler +// + +//============================================================= +// The default trivial text error handler. +//============================================================= +class JpGraphErrObject { + + protected $iTitle = "JpGraph error: "; + protected $iDest = false; + + + function __construct() { + // Empty. Reserved for future use + } + + function SetTitle($aTitle) { + $this->iTitle = $aTitle; + } + + function SetStrokeDest($aDest) { + $this->iDest = $aDest; + } + + // If aHalt is true then execution can't continue. Typical used for fatal errors + function Raise($aMsg,$aHalt=false) { + if( $this->iDest != '' ) { + if( $this->iDest == 'syslog' ) { + error_log($this->iTitle.$aMsg); + } + else { + $str = '['.date('r').'] '.$this->iTitle.$aMsg."\n"; + $f = @fopen($this->iDest,'a'); + if( $f ) { + @fwrite($f,$str); + @fclose($f); + } + } + } + else { + $aMsg = $this->iTitle.$aMsg; + // Check SAPI and if we are called from the command line + // send the error to STDERR instead + if( PHP_SAPI == 'cli' ) { + fwrite(STDERR,$aMsg); + } + else { + echo $aMsg; + } + } + if( $aHalt ) + exit(1); + } +} + +//============================================================== +// An image based error handler +//============================================================== +class JpGraphErrObjectImg extends JpGraphErrObject { + + function __construct() { + parent::__construct(); + // Empty. Reserved for future use + } + + function Raise($aMsg,$aHalt=true) { + $img_iconerror = + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'. + 'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. + 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'. + 'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'. + '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'. + 'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'. + 'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'. + 'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'. + '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'. + 'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'. + 'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'. + 'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'. + 'qL72fwAAAABJRU5ErkJggg==' ; + + + if( function_exists("imagetypes") ) { + $supported = imagetypes(); + } else { + $supported = 0; + } + + if( !function_exists('imagecreatefromstring') ) { + $supported = 0; + } + + if( ob_get_length() || headers_sent() || !($supported & IMG_PNG) ) { + // Special case for headers already sent or that the installation doesn't support + // the PNG format (which the error icon is encoded in). + // Dont return an image since it can't be displayed + die($this->iTitle.' '.$aMsg); + } + + $aMsg = wordwrap($aMsg,55); + $lines = substr_count($aMsg,"\n"); + + // Create the error icon GD + $erricon = Image::CreateFromString(base64_decode($img_iconerror)); + + // Create an image that contains the error text. + $w=400; + $h=100 + 15*max(0,$lines-3); + + $img = new Image($w,$h); + + + // Drop shadow + $img->SetColor("gray"); + $img->FilledRectangle(5,5,$w-1,$h-1,10); + $img->SetColor("gray:0.7"); + $img->FilledRectangle(5,5,$w-3,$h-3,10); + + // Window background + $img->SetColor("lightblue"); + $img->FilledRectangle(1,1,$w-5,$h-5); + $img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40); + + // Window border + $img->SetColor("black"); + $img->Rectangle(1,1,$w-5,$h-5); + $img->Rectangle(0,0,$w-4,$h-4); + + // Window top row + $img->SetColor("darkred"); + for($y=3; $y < 18; $y += 2 ) + $img->Line(1,$y,$w-6,$y); + + // "White shadow" + $img->SetColor("white"); + + // Left window edge + $img->Line(2,2,2,$h-5); + $img->Line(2,2,$w-6,2); + + // "Gray button shadow" + $img->SetColor("darkgray"); + + // Gray window shadow + $img->Line(2,$h-6,$w-5,$h-6); + $img->Line(3,$h-7,$w-5,$h-7); + + // Window title + $m = floor($w/2-5); + $l = 110; + $img->SetColor("lightgray:1.3"); + $img->FilledRectangle($m-$l,2,$m+$l,16); + + // Stroke text + $img->SetColor("darkred"); + $img->SetFont(FF_FONT2,FS_BOLD); + $img->StrokeText($m-90,15,$this->iTitle); + $img->SetColor("black"); + $img->SetFont(FF_FONT1,FS_NORMAL); + $txt = new Text($aMsg,52,25); + $txt->Align("left","top"); + $txt->Stroke($img); + if ($this->iDest) { + $img->Stream($this->iDest); + } else { + $img->Headers(); + $img->Stream(); + } + if( $aHalt ) + die(); + } +} + + + +if( ! USE_IMAGE_ERROR_HANDLER ) { + JpGraphError::SetImageFlag(false); +} +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_error.php b/ext/jpgraph-3.0.7/src/jpgraph_error.php index 9c11ce6..3ecef8d 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_error.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_error.php @@ -1,157 +1,157 @@ -numpoints /= 2; - } - //--------------- - // PUBLIC METHODS - - // Gets called before any axis are stroked - function PreStrokeAdjust($graph) { - if( $this->center ) { - $a=0.5; $b=0.5; - ++$this->numpoints; - } else { - $a=0; $b=0; - } - $graph->xaxis->scale->ticks->SetXLabelOffset($a); - $graph->SetTextScaleOff($b); - //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); - } - - // Method description - function Stroke($img,$xscale,$yscale) { - $numpoints=count($this->coords[0])/2; - $img->SetColor($this->color); - $img->SetLineWeight($this->weight); - - if( isset($this->coords[1]) ) { - if( count($this->coords[1])!=$numpoints ) - JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); - //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); - else - $exist_x = true; - } - else - $exist_x = false; - - for( $i=0; $i<$numpoints; ++$i) { - if( $exist_x ) - $x=$this->coords[1][$i]; - else - $x=$i; - - if( !is_numeric($x) || - !is_numeric($this->coords[0][$i*2]) || !is_numeric($this->coords[0][$i*2+1]) ) { - continue; - } - - $xt = $xscale->Translate($x); - $yt1 = $yscale->Translate($this->coords[0][$i*2]); - $yt2 = $yscale->Translate($this->coords[0][$i*2+1]); - $img->Line($xt,$yt1,$xt,$yt2); - $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1); - $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2); - } - return true; - } -} // Class - - -//=================================================== -// CLASS ErrorLinePlot -// Description: Combine a line and error plot -// THIS IS A DEPRECATED PLOT TYPE JUST KEPT FOR -// BACKWARD COMPATIBILITY -//=================================================== -class ErrorLinePlot extends ErrorPlot { - public $line=null; - //--------------- - // CONSTRUCTOR - function __construct($datay,$datax=false) { - parent::__construct($datay,$datax); - // Calculate line coordinates as the average of the error limits - $n = count($datay); - for($i=0; $i < $n; $i+=2 ) { - $ly[]=($datay[$i]+$datay[$i+1])/2; - } - $this->line=new LinePlot($ly,$datax); - } - - //--------------- - // PUBLIC METHODS - function Legend($graph) { - if( $this->legend != "" ) - $graph->legend->Add($this->legend,$this->color); - $this->line->Legend($graph); - } - - function Stroke($img,$xscale,$yscale) { - parent::Stroke($img,$xscale,$yscale); - $this->line->Stroke($img,$xscale,$yscale); - } -} // Class - - -//=================================================== -// CLASS LineErrorPlot -// Description: Combine a line and error plot -//=================================================== -class LineErrorPlot extends ErrorPlot { - public $line=null; - //--------------- - // CONSTRUCTOR - // Data is (val, errdeltamin, errdeltamax) - function __construct($datay,$datax=false) { - $ly=array(); $ey=array(); - $n = count($datay); - if( $n % 3 != 0 ) { - JpGraphError::RaiseL(4002); - //('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3'); - } - for($i=0; $i < $n; $i+=3 ) { - $ly[]=$datay[$i]; - $ey[]=$datay[$i]+$datay[$i+1]; - $ey[]=$datay[$i]+$datay[$i+2]; - } - parent::__construct($ey,$datax); - $this->line=new LinePlot($ly,$datax); - } - - //--------------- - // PUBLIC METHODS - function Legend($graph) { - if( $this->legend != "" ) - $graph->legend->Add($this->legend,$this->color); - $this->line->Legend($graph); - } - - function Stroke($img,$xscale,$yscale) { - parent::Stroke($img,$xscale,$yscale); - $this->line->Stroke($img,$xscale,$yscale); - } -} // Class - - -/* EOF */ +numpoints /= 2; + } + //--------------- + // PUBLIC METHODS + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + if( $this->center ) { + $a=0.5; $b=0.5; + ++$this->numpoints; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + + // Method description + function Stroke($img,$xscale,$yscale) { + $numpoints=count($this->coords[0])/2; + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) + JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); + //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + else + $exist_x = true; + } + else + $exist_x = false; + + for( $i=0; $i<$numpoints; ++$i) { + if( $exist_x ) + $x=$this->coords[1][$i]; + else + $x=$i; + + if( !is_numeric($x) || + !is_numeric($this->coords[0][$i*2]) || !is_numeric($this->coords[0][$i*2+1]) ) { + continue; + } + + $xt = $xscale->Translate($x); + $yt1 = $yscale->Translate($this->coords[0][$i*2]); + $yt2 = $yscale->Translate($this->coords[0][$i*2+1]); + $img->Line($xt,$yt1,$xt,$yt2); + $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1); + $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2); + } + return true; + } +} // Class + + +//=================================================== +// CLASS ErrorLinePlot +// Description: Combine a line and error plot +// THIS IS A DEPRECATED PLOT TYPE JUST KEPT FOR +// BACKWARD COMPATIBILITY +//=================================================== +class ErrorLinePlot extends ErrorPlot { + public $line=null; + //--------------- + // CONSTRUCTOR + function __construct($datay,$datax=false) { + parent::__construct($datay,$datax); + // Calculate line coordinates as the average of the error limits + $n = count($datay); + for($i=0; $i < $n; $i+=2 ) { + $ly[]=($datay[$i]+$datay[$i+1])/2; + } + $this->line=new LinePlot($ly,$datax); + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + if( $this->legend != "" ) + $graph->legend->Add($this->legend,$this->color); + $this->line->Legend($graph); + } + + function Stroke($img,$xscale,$yscale) { + parent::Stroke($img,$xscale,$yscale); + $this->line->Stroke($img,$xscale,$yscale); + } +} // Class + + +//=================================================== +// CLASS LineErrorPlot +// Description: Combine a line and error plot +//=================================================== +class LineErrorPlot extends ErrorPlot { + public $line=null; + //--------------- + // CONSTRUCTOR + // Data is (val, errdeltamin, errdeltamax) + function __construct($datay,$datax=false) { + $ly=array(); $ey=array(); + $n = count($datay); + if( $n % 3 != 0 ) { + JpGraphError::RaiseL(4002); + //('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3'); + } + for($i=0; $i < $n; $i+=3 ) { + $ly[]=$datay[$i]; + $ey[]=$datay[$i]+$datay[$i+1]; + $ey[]=$datay[$i]+$datay[$i+2]; + } + parent::__construct($ey,$datax); + $this->line=new LinePlot($ly,$datax); + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + if( $this->legend != "" ) + $graph->legend->Add($this->legend,$this->color); + $this->line->Legend($graph); + } + + function Stroke($img,$xscale,$yscale) { + parent::Stroke($img,$xscale,$yscale); + $this->line->Stroke($img,$xscale,$yscale); + } +} // Class + + +/* EOF */ ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_flags.php b/ext/jpgraph-3.0.7/src/jpgraph_flags.php index 95d107c..91e1bc5 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_flags.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_flags.php @@ -1,376 +1,376 @@ - 'afgh', - 'Republic of Angola' => 'agla', - 'Republic of Albania' => 'alba', - 'Alderney' => 'alde', - 'Democratic and Popular Republic of Algeria' => 'alge', - 'Territory of American Samoa' => 'amsa', - 'Principality of Andorra' => 'andr', - 'British Overseas Territory of Anguilla' => 'angu', - 'Antarctica' => 'anta', - 'Argentine Republic' => 'arge', - 'League of Arab States' => 'arle', - 'Republic of Armenia' => 'arme', - 'Aruba' => 'arub', - 'Commonwealth of Australia' => 'astl', - 'Republic of Austria' => 'aust', - 'Azerbaijani Republic' => 'azer', - 'Bangladesh' => 'bngl', - 'British Antarctic Territory' => 'bant', - 'Kingdom of Belgium' => 'belg', - 'British Overseas Territory of Bermuda' => 'berm', - 'Commonwealth of the Bahamas' => 'bhms', - 'Kingdom of Bahrain' => 'bhrn', - 'Republic of Belarus' => 'blru', - 'Republic of Bolivia' => 'blva', - 'Belize' => 'blze', - 'Republic of Benin' => 'bnin', - 'Republic of Botswana' => 'bots', - 'Federative Republic of Brazil' => 'braz', - 'Barbados' => 'brbd', - 'British Indian Ocean Territory' => 'brin', - 'Brunei Darussalam' => 'brun', - 'Republic of Burkina' => 'bufa', - 'Republic of Bulgaria' => 'bulg', - 'Republic of Burundi' => 'buru', - 'Overseas Territory of the British Virgin Islands' => 'bvis', - 'Central African Republic' => 'cafr', - 'Kingdom of Cambodia' => 'camb', - 'Republic of Cameroon' => 'came', - 'Dominion of Canada' => 'cana', - 'Caribbean Community' => 'cari', - 'Republic of Cape Verde' => 'cave', - 'Republic of Chad' => 'chad', - 'Republic of Chile' => 'chil', - 'Peoples Republic of China' => 'chin', - 'Territory of Christmas Island' => 'chms', - 'Commonwealth of Independent States' => 'cins', - 'Cook Islands' => 'ckis', - 'Republic of Colombia' => 'clmb', - 'Territory of Cocos Islands' => 'cois', - 'Commonwealth' => 'comn', - 'Union of the Comoros' => 'como', - 'Republic of the Congo' => 'cong', - 'Republic of Costa Rica' => 'corc', - 'Republic of Croatia' => 'croa', - 'Republic of Cuba' => 'cuba', - 'British Overseas Territory of the Cayman Islands' => 'cyis', - 'Republic of Cyprus' => 'cypr', - 'The Czech Republic' => 'czec', - 'Kingdom of Denmark' => 'denm', - 'Republic of Djibouti' => 'djib', - 'Commonwealth of Dominica' => 'domn', - 'Dominican Republic' => 'dore', - 'Republic of Ecuador' => 'ecua', - 'Arab Republic of Egypt' => 'egyp', - 'Republic of El Salvador' => 'elsa', - 'England' => 'engl', - 'Republic of Equatorial Guinea' => 'eqgu', - 'State of Eritrea' => 'erit', - 'Republic of Estonia' => 'estn', - 'Ethiopia' => 'ethp', - 'European Union' => 'euun', - 'British Overseas Territory of the Falkland Islands' => 'fais', - 'International Federation of Vexillological Associations' => 'fiav', - 'Republic of Fiji' => 'fiji', - 'Republic of Finland' => 'finl', - 'Territory of French Polynesia' => 'fpol', - 'French Republic' => 'fran', - 'Overseas Department of French Guiana' => 'frgu', - 'Gabonese Republic' => 'gabn', - 'Republic of the Gambia' => 'gamb', - 'Republic of Georgia' => 'geor', - 'Federal Republic of Germany' => 'germ', - 'Republic of Ghana' => 'ghan', - 'Gibraltar' => 'gibr', - 'Hellenic Republic' => 'grec', - 'State of Grenada' => 'gren', - 'Overseas Department of Guadeloupe' => 'guad', - 'Territory of Guam' => 'guam', - 'Republic of Guatemala' => 'guat', - 'The Bailiwick of Guernsey' => 'guer', - 'Republic of Guinea' => 'guin', - 'Republic of Haiti' => 'hait', - 'Hong Kong Special Administrative Region' => 'hokn', - 'Republic of Honduras' => 'hond', - 'Republic of Hungary' => 'hung', - 'Republic of Iceland' => 'icel', - 'International Committee of the Red Cross' => 'icrc', - 'Republic of India' => 'inda', - 'Republic of Indonesia' => 'indn', - 'Republic of Iraq' => 'iraq', - 'Republic of Ireland' => 'irel', - 'Organization of the Islamic Conference' => 'isco', - 'Isle of Man' => 'isma', - 'State of Israel' => 'isra', - 'Italian Republic' => 'ital', - 'Jamaica' => 'jama', - 'Japan' => 'japa', - 'The Bailiwick of Jersey' => 'jers', - 'Hashemite Kingdom of Jordan' => 'jord', - 'Republic of Kazakhstan' => 'kazk', - 'Republic of Kenya' => 'keny', - 'Republic of Kiribati' => 'kirb', - 'State of Kuwait' => 'kuwa', - 'Kyrgyz Republic' => 'kyrg', - 'Republic of Latvia' => 'latv', - 'Lebanese Republic' => 'leba', - 'Kingdom of Lesotho' => 'lest', - 'Republic of Liberia' => 'libe', - 'Principality of Liechtenstein' => 'liec', - 'Republic of Lithuania' => 'lith', - 'Grand Duchy of Luxembourg' => 'luxe', - 'Macao Special Administrative Region' => 'maca', - 'Republic of Macedonia' => 'mace', - 'Republic of Madagascar' => 'mada', - 'Republic of the Marshall Islands' => 'mais', - 'Republic of Mali' => 'mali', - 'Federation of Malaysia' => 'mals', - 'Republic of Malta' => 'malt', - 'Republic of Malawi' => 'malw', - 'Overseas Department of Martinique' => 'mart', - 'Islamic Republic of Mauritania' => 'maur', - 'Territorial Collectivity of Mayotte' => 'mayt', - 'United Mexican States' => 'mexc', - 'Federated States of Micronesia' => 'micr', - 'Midway Islands' => 'miis', - 'Republic of Moldova' => 'mold', - 'Principality of Monaco' => 'mona', - 'Republic of Mongolia' => 'mong', - 'British Overseas Territory of Montserrat' => 'mont', - 'Kingdom of Morocco' => 'morc', - 'Republic of Mozambique' => 'moza', - 'Republic of Mauritius' => 'mrts', - 'Union of Myanmar' => 'myan', - 'Republic of Namibia' => 'namb', - 'North Atlantic Treaty Organization' => 'nato', - 'Republic of Nauru' => 'naur', - 'Turkish Republic of Northern Cyprus' => 'ncyp', - 'Netherlands Antilles' => 'nean', - 'Kingdom of Nepal' => 'nepa', - 'Kingdom of the Netherlands' => 'neth', - 'Territory of Norfolk Island' => 'nfis', - 'Federal Republic of Nigeria' => 'ngra', - 'Republic of Nicaragua' => 'nica', - 'Republic of Niger' => 'nigr', - 'Niue' => 'niue', - 'Commonwealth of the Northern Mariana Islands' => 'nmar', - 'Province of Northern Ireland' => 'noir', - 'Nordic Council' => 'nord', - 'Kingdom of Norway' => 'norw', - 'Territory of New Caledonia and Dependencies' => 'nwca', - 'New Zealand' => 'nwze', - 'Organization of American States' => 'oast', - 'Organization of African Unity' => 'oaun', - 'International Olympic Committee' => 'olym', - 'Sultanate of Oman' => 'oman', - 'Islamic Republic of Pakistan' => 'paks', - 'Republic of Palau' => 'pala', - 'Independent State of Papua New Guinea' => 'pang', - 'Republic of Paraguay' => 'para', - 'Republic of Peru' => 'peru', - 'Republic of the Philippines' => 'phil', - 'British Overseas Territory of the Pitcairn Islands' => 'piis', - 'Republic of Poland' => 'pola', - 'Republic of Portugal' => 'port', - 'Commonwealth of Puerto Rico' => 'purc', - 'State of Qatar' => 'qata', - 'Russian Federation' => 'russ', - 'Romania' => 'rmna', - 'Republic of Rwanda' => 'rwan', - 'Kingdom of Saudi Arabia' => 'saar', - 'Republic of San Marino' => 'sama', - 'Nordic Sami Conference' => 'sami', - 'Sark' => 'sark', - 'Scotland' => 'scot', - 'Principality of Seborga' => 'sebo', - 'Republic of Serbia' => 'serb', - 'Republic of Sierra Leone' => 'sile', - 'Republic of Singapore' => 'sing', - 'Republic of Korea' => 'skor', - 'Republic of Slovenia' => 'slva', - 'Somali Republic' => 'smla', - 'Republic of Somaliland' => 'smld', - 'Republic of South Africa' => 'soaf', - 'Solomon Islands' => 'sois', - 'Kingdom of Spain' => 'span', - 'Secretariat of the Pacific Community' => 'spco', - 'Democratic Socialist Republic of Sri Lanka' => 'srla', - 'Saint Lucia' => 'stlu', - 'Republic of the Sudan' => 'suda', - 'Republic of Suriname' => 'surn', - 'Slovak Republic' => 'svka', - 'Kingdom of Sweden' => 'swdn', - 'Swiss Confederation' => 'swit', - 'Syrian Arab Republic' => 'syra', - 'Kingdom of Swaziland' => 'szld', - 'Republic of China' => 'taiw', - 'Taiwan' => 'taiw', - 'Republic of Tajikistan' => 'tajk', - 'United Republic of Tanzania' => 'tanz', - 'Kingdom of Thailand' => 'thal', - 'Autonomous Region of Tibet' => 'tibe', - 'Turkmenistan' => 'tkst', - 'Togolese Republic' => 'togo', - 'Tokelau' => 'toke', - 'Kingdom of Tonga' => 'tong', - 'Tristan da Cunha' => 'trdc', - 'Tromelin' => 'tris', - 'Republic of Tunisia' => 'tuns', - 'Republic of Turkey' => 'turk', - 'Tuvalu' => 'tuva', - 'United Arab Emirates' => 'uaem', - 'Republic of Uganda' => 'ugan', - 'Ukraine' => 'ukrn', - 'United Kingdom of Great Britain' => 'unkg', - 'United Nations' => 'unna', - 'United States of America' => 'unst', - 'Oriental Republic of Uruguay' => 'urgy', - 'Virgin Islands of the United States' => 'usvs', - 'Republic of Uzbekistan' => 'uzbk', - 'State of the Vatican City' => 'vacy', - 'Republic of Vanuatu' => 'vant', - 'Bolivarian Republic of Venezuela' => 'venz', - 'Republic of Yemen' => 'yemn', - 'Democratic Republic of Congo' => 'zare', - 'Republic of Zimbabwe' => 'zbwe' ) ; - - - private $iFlagCount = -1; - private $iFlagSetMap = array( - FLAGSIZE1 => 'flags_thumb35x35', - FLAGSIZE2 => 'flags_thumb60x60', - FLAGSIZE3 => 'flags_thumb100x100', - FLAGSIZE4 => 'flags' - ); - - private $iFlagData ; - private $iOrdIdx=array(); - - function FlagImages($aSize=FLAGSIZE1) { - switch($aSize) { - case FLAGSIZE1 : - case FLAGSIZE2 : - case FLAGSIZE3 : - case FLAGSIZE4 : - $file = dirname(__FILE__).'/'.$this->iFlagSetMap[$aSize].'.dat'; - $fp = fopen($file,'rb'); - $rawdata = fread($fp,filesize($file)); - $this->iFlagData = unserialize($rawdata); - break; - default: - JpGraphError::RaiseL(5001,$aSize); - //('Unknown flag size. ('.$aSize.')'); - } - $this->iFlagCount = count($this->iCountryNameMap); - } - - function GetNum() { - return $this->iFlagCount; - } - - function GetImgByName($aName,&$outFullName) { - $idx = $this->GetIdxByName($aName,$outFullName); - return $this->GetImgByIdx($idx); - } - - function GetImgByIdx($aIdx) { - if( array_key_exists($aIdx,$this->iFlagData) ) { - $d = $this->iFlagData[$aIdx][1]; - return Image::CreateFromString($d); - } - else { - JpGraphError::RaiseL(5002,$aIdx); - //("Flag index \"ï¿œ$aIdx\" does not exist."); - } - } - - function GetIdxByOrdinal($aOrd,&$outFullName) { - $aOrd--; - $n = count($this->iOrdIdx); - if( $n == 0 ) { - reset($this->iCountryNameMap); - $this->iOrdIdx=array(); - $i=0; - while( list($key,$val) = each($this->iCountryNameMap) ) { - $this->iOrdIdx[$i++] = array($val,$key); - } - $tmp=$this->iOrdIdx[$aOrd]; - $outFullName = $tmp[1]; - return $tmp[0]; - - } - elseif( $aOrd >= 0 && $aOrd < $n ) { - $tmp=$this->iOrdIdx[$aOrd]; - $outFullName = $tmp[1]; - return $tmp[0]; - } - else { - JpGraphError::RaiseL(5003,$aOrd); - //('Invalid ordinal number specified for flag index.'); - } - } - - function GetIdxByName($aName,&$outFullName) { - - if( is_integer($aName) ) { - $idx = $this->GetIdxByOrdinal($aName,$outFullName); - return $idx; - } - - $found=false; - $aName = strtolower($aName); - $nlen = strlen($aName); - reset($this->iCountryNameMap); - // Start by trying to match exact index name - while( list($key,$val) = each($this->iCountryNameMap) ) { - if( $nlen == strlen($val) && $val == $aName ) { - $found=true; - break; - } - } - if( !$found ) { - reset($this->iCountryNameMap); - // If the exact index doesn't work try a (partial) full name - while( list($key,$val) = each($this->iCountryNameMap) ) { - if( strpos(strtolower($key), $aName) !== false ) { - $found=true; - break; - } - } - } - if( $found ) { - $outFullName = $key; - return $val; - } - else { - JpGraphError::RaiseL(5004,$aName); - //("The (partial) country name \"$aName\" does not have a cooresponding flag image. The flag may still exist but under another name, e.g. insted of \"usa\" try \"united states\"."); - } - } -} - - - - + 'afgh', + 'Republic of Angola' => 'agla', + 'Republic of Albania' => 'alba', + 'Alderney' => 'alde', + 'Democratic and Popular Republic of Algeria' => 'alge', + 'Territory of American Samoa' => 'amsa', + 'Principality of Andorra' => 'andr', + 'British Overseas Territory of Anguilla' => 'angu', + 'Antarctica' => 'anta', + 'Argentine Republic' => 'arge', + 'League of Arab States' => 'arle', + 'Republic of Armenia' => 'arme', + 'Aruba' => 'arub', + 'Commonwealth of Australia' => 'astl', + 'Republic of Austria' => 'aust', + 'Azerbaijani Republic' => 'azer', + 'Bangladesh' => 'bngl', + 'British Antarctic Territory' => 'bant', + 'Kingdom of Belgium' => 'belg', + 'British Overseas Territory of Bermuda' => 'berm', + 'Commonwealth of the Bahamas' => 'bhms', + 'Kingdom of Bahrain' => 'bhrn', + 'Republic of Belarus' => 'blru', + 'Republic of Bolivia' => 'blva', + 'Belize' => 'blze', + 'Republic of Benin' => 'bnin', + 'Republic of Botswana' => 'bots', + 'Federative Republic of Brazil' => 'braz', + 'Barbados' => 'brbd', + 'British Indian Ocean Territory' => 'brin', + 'Brunei Darussalam' => 'brun', + 'Republic of Burkina' => 'bufa', + 'Republic of Bulgaria' => 'bulg', + 'Republic of Burundi' => 'buru', + 'Overseas Territory of the British Virgin Islands' => 'bvis', + 'Central African Republic' => 'cafr', + 'Kingdom of Cambodia' => 'camb', + 'Republic of Cameroon' => 'came', + 'Dominion of Canada' => 'cana', + 'Caribbean Community' => 'cari', + 'Republic of Cape Verde' => 'cave', + 'Republic of Chad' => 'chad', + 'Republic of Chile' => 'chil', + 'Peoples Republic of China' => 'chin', + 'Territory of Christmas Island' => 'chms', + 'Commonwealth of Independent States' => 'cins', + 'Cook Islands' => 'ckis', + 'Republic of Colombia' => 'clmb', + 'Territory of Cocos Islands' => 'cois', + 'Commonwealth' => 'comn', + 'Union of the Comoros' => 'como', + 'Republic of the Congo' => 'cong', + 'Republic of Costa Rica' => 'corc', + 'Republic of Croatia' => 'croa', + 'Republic of Cuba' => 'cuba', + 'British Overseas Territory of the Cayman Islands' => 'cyis', + 'Republic of Cyprus' => 'cypr', + 'The Czech Republic' => 'czec', + 'Kingdom of Denmark' => 'denm', + 'Republic of Djibouti' => 'djib', + 'Commonwealth of Dominica' => 'domn', + 'Dominican Republic' => 'dore', + 'Republic of Ecuador' => 'ecua', + 'Arab Republic of Egypt' => 'egyp', + 'Republic of El Salvador' => 'elsa', + 'England' => 'engl', + 'Republic of Equatorial Guinea' => 'eqgu', + 'State of Eritrea' => 'erit', + 'Republic of Estonia' => 'estn', + 'Ethiopia' => 'ethp', + 'European Union' => 'euun', + 'British Overseas Territory of the Falkland Islands' => 'fais', + 'International Federation of Vexillological Associations' => 'fiav', + 'Republic of Fiji' => 'fiji', + 'Republic of Finland' => 'finl', + 'Territory of French Polynesia' => 'fpol', + 'French Republic' => 'fran', + 'Overseas Department of French Guiana' => 'frgu', + 'Gabonese Republic' => 'gabn', + 'Republic of the Gambia' => 'gamb', + 'Republic of Georgia' => 'geor', + 'Federal Republic of Germany' => 'germ', + 'Republic of Ghana' => 'ghan', + 'Gibraltar' => 'gibr', + 'Hellenic Republic' => 'grec', + 'State of Grenada' => 'gren', + 'Overseas Department of Guadeloupe' => 'guad', + 'Territory of Guam' => 'guam', + 'Republic of Guatemala' => 'guat', + 'The Bailiwick of Guernsey' => 'guer', + 'Republic of Guinea' => 'guin', + 'Republic of Haiti' => 'hait', + 'Hong Kong Special Administrative Region' => 'hokn', + 'Republic of Honduras' => 'hond', + 'Republic of Hungary' => 'hung', + 'Republic of Iceland' => 'icel', + 'International Committee of the Red Cross' => 'icrc', + 'Republic of India' => 'inda', + 'Republic of Indonesia' => 'indn', + 'Republic of Iraq' => 'iraq', + 'Republic of Ireland' => 'irel', + 'Organization of the Islamic Conference' => 'isco', + 'Isle of Man' => 'isma', + 'State of Israel' => 'isra', + 'Italian Republic' => 'ital', + 'Jamaica' => 'jama', + 'Japan' => 'japa', + 'The Bailiwick of Jersey' => 'jers', + 'Hashemite Kingdom of Jordan' => 'jord', + 'Republic of Kazakhstan' => 'kazk', + 'Republic of Kenya' => 'keny', + 'Republic of Kiribati' => 'kirb', + 'State of Kuwait' => 'kuwa', + 'Kyrgyz Republic' => 'kyrg', + 'Republic of Latvia' => 'latv', + 'Lebanese Republic' => 'leba', + 'Kingdom of Lesotho' => 'lest', + 'Republic of Liberia' => 'libe', + 'Principality of Liechtenstein' => 'liec', + 'Republic of Lithuania' => 'lith', + 'Grand Duchy of Luxembourg' => 'luxe', + 'Macao Special Administrative Region' => 'maca', + 'Republic of Macedonia' => 'mace', + 'Republic of Madagascar' => 'mada', + 'Republic of the Marshall Islands' => 'mais', + 'Republic of Mali' => 'mali', + 'Federation of Malaysia' => 'mals', + 'Republic of Malta' => 'malt', + 'Republic of Malawi' => 'malw', + 'Overseas Department of Martinique' => 'mart', + 'Islamic Republic of Mauritania' => 'maur', + 'Territorial Collectivity of Mayotte' => 'mayt', + 'United Mexican States' => 'mexc', + 'Federated States of Micronesia' => 'micr', + 'Midway Islands' => 'miis', + 'Republic of Moldova' => 'mold', + 'Principality of Monaco' => 'mona', + 'Republic of Mongolia' => 'mong', + 'British Overseas Territory of Montserrat' => 'mont', + 'Kingdom of Morocco' => 'morc', + 'Republic of Mozambique' => 'moza', + 'Republic of Mauritius' => 'mrts', + 'Union of Myanmar' => 'myan', + 'Republic of Namibia' => 'namb', + 'North Atlantic Treaty Organization' => 'nato', + 'Republic of Nauru' => 'naur', + 'Turkish Republic of Northern Cyprus' => 'ncyp', + 'Netherlands Antilles' => 'nean', + 'Kingdom of Nepal' => 'nepa', + 'Kingdom of the Netherlands' => 'neth', + 'Territory of Norfolk Island' => 'nfis', + 'Federal Republic of Nigeria' => 'ngra', + 'Republic of Nicaragua' => 'nica', + 'Republic of Niger' => 'nigr', + 'Niue' => 'niue', + 'Commonwealth of the Northern Mariana Islands' => 'nmar', + 'Province of Northern Ireland' => 'noir', + 'Nordic Council' => 'nord', + 'Kingdom of Norway' => 'norw', + 'Territory of New Caledonia and Dependencies' => 'nwca', + 'New Zealand' => 'nwze', + 'Organization of American States' => 'oast', + 'Organization of African Unity' => 'oaun', + 'International Olympic Committee' => 'olym', + 'Sultanate of Oman' => 'oman', + 'Islamic Republic of Pakistan' => 'paks', + 'Republic of Palau' => 'pala', + 'Independent State of Papua New Guinea' => 'pang', + 'Republic of Paraguay' => 'para', + 'Republic of Peru' => 'peru', + 'Republic of the Philippines' => 'phil', + 'British Overseas Territory of the Pitcairn Islands' => 'piis', + 'Republic of Poland' => 'pola', + 'Republic of Portugal' => 'port', + 'Commonwealth of Puerto Rico' => 'purc', + 'State of Qatar' => 'qata', + 'Russian Federation' => 'russ', + 'Romania' => 'rmna', + 'Republic of Rwanda' => 'rwan', + 'Kingdom of Saudi Arabia' => 'saar', + 'Republic of San Marino' => 'sama', + 'Nordic Sami Conference' => 'sami', + 'Sark' => 'sark', + 'Scotland' => 'scot', + 'Principality of Seborga' => 'sebo', + 'Republic of Serbia' => 'serb', + 'Republic of Sierra Leone' => 'sile', + 'Republic of Singapore' => 'sing', + 'Republic of Korea' => 'skor', + 'Republic of Slovenia' => 'slva', + 'Somali Republic' => 'smla', + 'Republic of Somaliland' => 'smld', + 'Republic of South Africa' => 'soaf', + 'Solomon Islands' => 'sois', + 'Kingdom of Spain' => 'span', + 'Secretariat of the Pacific Community' => 'spco', + 'Democratic Socialist Republic of Sri Lanka' => 'srla', + 'Saint Lucia' => 'stlu', + 'Republic of the Sudan' => 'suda', + 'Republic of Suriname' => 'surn', + 'Slovak Republic' => 'svka', + 'Kingdom of Sweden' => 'swdn', + 'Swiss Confederation' => 'swit', + 'Syrian Arab Republic' => 'syra', + 'Kingdom of Swaziland' => 'szld', + 'Republic of China' => 'taiw', + 'Taiwan' => 'taiw', + 'Republic of Tajikistan' => 'tajk', + 'United Republic of Tanzania' => 'tanz', + 'Kingdom of Thailand' => 'thal', + 'Autonomous Region of Tibet' => 'tibe', + 'Turkmenistan' => 'tkst', + 'Togolese Republic' => 'togo', + 'Tokelau' => 'toke', + 'Kingdom of Tonga' => 'tong', + 'Tristan da Cunha' => 'trdc', + 'Tromelin' => 'tris', + 'Republic of Tunisia' => 'tuns', + 'Republic of Turkey' => 'turk', + 'Tuvalu' => 'tuva', + 'United Arab Emirates' => 'uaem', + 'Republic of Uganda' => 'ugan', + 'Ukraine' => 'ukrn', + 'United Kingdom of Great Britain' => 'unkg', + 'United Nations' => 'unna', + 'United States of America' => 'unst', + 'Oriental Republic of Uruguay' => 'urgy', + 'Virgin Islands of the United States' => 'usvs', + 'Republic of Uzbekistan' => 'uzbk', + 'State of the Vatican City' => 'vacy', + 'Republic of Vanuatu' => 'vant', + 'Bolivarian Republic of Venezuela' => 'venz', + 'Republic of Yemen' => 'yemn', + 'Democratic Republic of Congo' => 'zare', + 'Republic of Zimbabwe' => 'zbwe' ) ; + + + private $iFlagCount = -1; + private $iFlagSetMap = array( + FLAGSIZE1 => 'flags_thumb35x35', + FLAGSIZE2 => 'flags_thumb60x60', + FLAGSIZE3 => 'flags_thumb100x100', + FLAGSIZE4 => 'flags' + ); + + private $iFlagData ; + private $iOrdIdx=array(); + + function FlagImages($aSize=FLAGSIZE1) { + switch($aSize) { + case FLAGSIZE1 : + case FLAGSIZE2 : + case FLAGSIZE3 : + case FLAGSIZE4 : + $file = dirname(__FILE__).'/'.$this->iFlagSetMap[$aSize].'.dat'; + $fp = fopen($file,'rb'); + $rawdata = fread($fp,filesize($file)); + $this->iFlagData = unserialize($rawdata); + break; + default: + JpGraphError::RaiseL(5001,$aSize); + //('Unknown flag size. ('.$aSize.')'); + } + $this->iFlagCount = count($this->iCountryNameMap); + } + + function GetNum() { + return $this->iFlagCount; + } + + function GetImgByName($aName,&$outFullName) { + $idx = $this->GetIdxByName($aName,$outFullName); + return $this->GetImgByIdx($idx); + } + + function GetImgByIdx($aIdx) { + if( array_key_exists($aIdx,$this->iFlagData) ) { + $d = $this->iFlagData[$aIdx][1]; + return Image::CreateFromString($d); + } + else { + JpGraphError::RaiseL(5002,$aIdx); + //("Flag index \"ï¿œ$aIdx\" does not exist."); + } + } + + function GetIdxByOrdinal($aOrd,&$outFullName) { + $aOrd--; + $n = count($this->iOrdIdx); + if( $n == 0 ) { + reset($this->iCountryNameMap); + $this->iOrdIdx=array(); + $i=0; + while( list($key,$val) = each($this->iCountryNameMap) ) { + $this->iOrdIdx[$i++] = array($val,$key); + } + $tmp=$this->iOrdIdx[$aOrd]; + $outFullName = $tmp[1]; + return $tmp[0]; + + } + elseif( $aOrd >= 0 && $aOrd < $n ) { + $tmp=$this->iOrdIdx[$aOrd]; + $outFullName = $tmp[1]; + return $tmp[0]; + } + else { + JpGraphError::RaiseL(5003,$aOrd); + //('Invalid ordinal number specified for flag index.'); + } + } + + function GetIdxByName($aName,&$outFullName) { + + if( is_integer($aName) ) { + $idx = $this->GetIdxByOrdinal($aName,$outFullName); + return $idx; + } + + $found=false; + $aName = strtolower($aName); + $nlen = strlen($aName); + reset($this->iCountryNameMap); + // Start by trying to match exact index name + while( list($key,$val) = each($this->iCountryNameMap) ) { + if( $nlen == strlen($val) && $val == $aName ) { + $found=true; + break; + } + } + if( !$found ) { + reset($this->iCountryNameMap); + // If the exact index doesn't work try a (partial) full name + while( list($key,$val) = each($this->iCountryNameMap) ) { + if( strpos(strtolower($key), $aName) !== false ) { + $found=true; + break; + } + } + } + if( $found ) { + $outFullName = $key; + return $val; + } + else { + JpGraphError::RaiseL(5004,$aName); + //("The (partial) country name \"$aName\" does not have a cooresponding flag image. The flag may still exist but under another name, e.g. insted of \"usa\" try \"united states\"."); + } + } +} + + + + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_gantt.php b/ext/jpgraph-3.0.7/src/jpgraph_gantt.php index b8f0e5f..3ae2d2e 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_gantt.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_gantt.php @@ -1,3955 +1,3955 @@ -vgrid = new LineProperty(); - } - - function Hide($aF=true) { - $this->iShow=!$aF; - } - - function Show($aF=true) { - $this->iShow=$aF; - } - - // Specify font - function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { - $this->iFFamily = $aFFamily; - $this->iFStyle = $aFStyle; - $this->iFSize = $aFSize; - } - - function SetStyle($aStyle) { - $this->iStyle = $aStyle; - } - - function SetColumnMargin($aLeft,$aRight) { - $this->iLeftColMargin = $aLeft; - $this->iRightColMargin = $aRight; - } - - function SetFontColor($aFontColor) { - $this->iFontColor = $aFontColor; - } - - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function SetBackgroundColor($aColor) { - $this->iBackgroundColor = $aColor; - } - - function SetColTitles($aTitles,$aWidth=null) { - $this->iTitles = $aTitles; - $this->iWidth = $aWidth; - } - - function SetMinColWidth($aWidths) { - $n = min(count($this->iTitles),count($aWidths)); - for($i=0; $i < $n; ++$i ) { - if( !empty($aWidths[$i]) ) { - if( empty($this->iWidth[$i]) ) { - $this->iWidth[$i] = $aWidths[$i]; - } - else { - $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]); - } - } - } - } - - function GetWidth($aImg) { - $txt = new TextProperty(); - $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - $n = count($this->iTitles) ; - $rm=$this->iRightColMargin; - $w = 0; - for($h=0, $i=0; $i < $n; ++$i ) { - $w += $this->iLeftColMargin; - $txt->Set($this->iTitles[$i]); - if( !empty($this->iWidth[$i]) ) { - $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]); - } - else { - $w1 = $txt->GetWidth($aImg)+$rm; - } - $this->iWidth[$i] = $w1; - $w += $w1; - $h = max($h,$txt->GetHeight($aImg)); - } - $this->iHeight = $h+$this->iTopHeaderMargin; - $txt=''; - return $w; - } - - function GetColStart($aImg,&$aStart,$aAddLeftMargin=false) { - $n = count($this->iTitles) ; - $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0; - $aStart=array($aImg->left_margin+$adj); - for( $i=1; $i < $n; ++$i ) { - $aStart[$i] = $aStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1]; - } - } - - // Adjust headers left, right or centered - function SetHeaderAlign($aAlign) { - $this->iHeaderAlign=$aAlign; - } - - function Stroke($aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) { - - if( !$this->iShow ) return; - - $txt = new TextProperty(); - $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - $txt->SetColor($this->iFontColor); - $txt->SetAlign($this->iHeaderAlign,'top'); - $n=count($this->iTitles); - - if( $n == 0 ) - return; - - $x = $aXLeft; - $h = $this->iHeight; - $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ; - - if( $h < 0 ) { - JpGraphError::RaiseL(6001); - //('Internal error. Height for ActivityTitles is < 0'); - } - - $aImg->SetLineWeight(1); - // Set background color - $aImg->SetColor($this->iBackgroundColor); - $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1); - - if( $this->iStyle == 1 ) { - // Make a 3D effect - $aImg->SetColor('white'); - $aImg->Line($aXLeft,$yTop+1,$aXRight,$yTop+1); - } - - for($i=0; $i < $n; ++$i ) { - if( $this->iStyle == 1 ) { - // Make a 3D effect - $aImg->SetColor('white'); - $aImg->Line($x+1,$yTop,$x+1,$aYBottom); - } - $x += $this->iLeftColMargin; - $txt->Set($this->iTitles[$i]); - - // Adjust the text anchor position according to the choosen alignment - $xp = $x; - if( $this->iHeaderAlign == 'center' ) { - $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2; - } - elseif( $this->iHeaderAlign == 'right' ) { - $xp = $x +$this->iWidth[$i]-$this->iRightColMargin; - } - - $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin); - $x += $this->iWidth[$i]; - if( $i < $n-1 ) { - $aImg->SetColor($this->iColor); - $aImg->Line($x,$yTop,$x,$aYBottom); - } - } - - $aImg->SetColor($this->iColor); - $aImg->Line($aXLeft,$yTop, $aXRight,$yTop); - - // Stroke vertical column dividers - $cols=array(); - $this->GetColStart($aImg,$cols); - $n=count($cols); - for( $i=1; $i < $n; ++$i ) { - $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i], - $aImg->height - $aImg->bottom_margin); - } - } -} - - -//=================================================== -// CLASS GanttGraph -// Description: Main class to handle gantt graphs -//=================================================== -class GanttGraph extends Graph { - public $scale; // Public accessible - public $hgrid=null; - private $iObj=array(); // Gantt objects - private $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels - private $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label - private $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN - private $iSimpleFont = FF_FONT1,$iSimpleFontSize=11; - private $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red'; - private $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen'; - private $iSimpleProgressStyle=GANTT_SOLID; - private $iZoomFactor = 1.0; - //--------------- - // CONSTRUCTOR - // Create a new gantt graph - function __construct($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) { - - // Backward compatibility - if( $aWidth == -1 ) $aWidth=0; - if( $aHeight == -1 ) $aHeight=0; - - if( $aWidth< 0 || $aHeight < 0 ) { - JpgraphError::RaiseL(6002); - //("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension."); - } - parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); - $this->scale = new GanttScale($this->img); - - // Default margins - $this->img->SetMargin(15,17,25,15); - - $this->hgrid = new HorizontalGridLine(); - - $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); - $this->SetBox(); - } - - //--------------- - // PUBLIC METHODS - - // - - function SetSimpleFont($aFont,$aSize) { - $this->iSimpleFont = $aFont; - $this->iSimpleFontSize = $aSize; - } - - function SetSimpleStyle($aBand,$aColor,$aBkgColor) { - $this->iSimpleStyle = $aBand; - $this->iSimpleColor = $aColor; - $this->iSimpleBkgColor = $aBkgColor; - } - - // A utility function to help create basic Gantt charts - function CreateSimple($data,$constrains=array(),$progress=array()) { - $num = count($data); - for( $i=0; $i < $num; ++$i) { - switch( $data[$i][1] ) { - case ACTYPE_GROUP: - // Create a slightly smaller height bar since the - // "wings" at the end will make it look taller - $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8); - $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize); - $a->rightMark->Show(); - $a->rightMark->SetType(MARK_RIGHTTRIANGLE); - $a->rightMark->SetWidth(8); - $a->rightMark->SetColor('black'); - $a->rightMark->SetFillColor('black'); - - $a->leftMark->Show(); - $a->leftMark->SetType(MARK_LEFTTRIANGLE); - $a->leftMark->SetWidth(8); - $a->leftMark->SetColor('black'); - $a->leftMark->SetFillColor('black'); - - $a->SetPattern(BAND_SOLID,'black'); - $csimpos = 6; - break; - - case ACTYPE_NORMAL: - $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10); - $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); - $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor); - $a->SetFillColor($this->iSimpleBkgColor); - // Check if this activity should have a constrain line - $n = count($constrains); - for( $j=0; $j < $n; ++$j ) { - if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) { - JpGraphError::RaiseL(6003,$j); - //("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)"); - } - if( $constrains[$j][0]==$data[$i][0] ) { - $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID); - } - } - - // Check if this activity have a progress bar - $n = count($progress); - for( $j=0; $j < $n; ++$j ) { - - if( empty($progress[$j]) || (count($progress[$j]) != 2) ) { - JpGraphError::RaiseL(6004,$j); - //("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)"); - } - if( $progress[$j][0]==$data[$i][0] ) { - $a->progress->Set($progress[$j][1]); - $a->progress->SetPattern($this->iSimpleProgressStyle, - $this->iSimpleProgressColor); - $a->progress->SetFillColor($this->iSimpleProgressBkgColor); - //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]); - break; - } - } - $csimpos = 6; - break; - - case ACTYPE_MILESTONE: - $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]); - $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); - $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); - $csimpos = 5; - break; - default: - die('Unknown activity type'); - break; - } - - // Setup caption - $a->caption->Set($data[$i][$csimpos-1]); - - // Check if this activity should have a CSIM targetï¿œ? - if( !empty($data[$i][$csimpos]) ) { - $a->SetCSIMTarget($data[$i][$csimpos]); - $a->SetCSIMAlt($data[$i][$csimpos+1]); - } - if( !empty($data[$i][$csimpos+2]) ) { - $a->title->SetCSIMTarget($data[$i][$csimpos+2]); - $a->title->SetCSIMAlt($data[$i][$csimpos+3]); - } - - $this->Add($a); - } - } - - // Set user specified scale zoom factor when auto sizing is used - function SetZoomFactor($aZoom) { - $this->iZoomFactor = $aZoom; - } - - - // Set what headers should be shown - function ShowHeaders($aFlg) { - $this->scale->ShowHeaders($aFlg); - } - - // Specify the fraction of the font height that should be added - // as vertical margin - function SetLabelVMarginFactor($aVal) { - $this->iLabelVMarginFactor = $aVal; - } - - // Synonym to the method above - function SetVMarginFactor($aVal) { - $this->iLabelVMarginFactor = $aVal; - } - - - // Add a new Gantt object - function Add($aObject) { - if( is_array($aObject) && count($aObject) > 0 ) { - $cl = $aObject[0]; - if( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) { - $this->AddIcon($aObject); - } - elseif( class_exists('Text',false) && ($cl instanceof Text) ) { - $this->AddText($aObject); - } - else { - $n = count($aObject); - for($i=0; $i < $n; ++$i) - $this->iObj[] = $aObject[$i]; - } - } - else { - if( class_exists('IconPlot',false) && ($aObject instanceof IconPlot) ) { - $this->AddIcon($aObject); - } - elseif( class_exists('Text',false) && ($aObject instanceof Text) ) { - $this->AddText($aObject); - } - else { - $this->iObj[] = $aObject; - } - } - } - - function StrokeTexts() { - // Stroke any user added text objects - if( $this->texts != null ) { - $n = count($this->texts); - for($i=0; $i < $n; ++$i) { - if( $this->texts[$i]->iScalePosX !== null && $this->texts[$i]->iScalePosY !== null ) { - $x = $this->scale->TranslateDate($this->texts[$i]->iScalePosX); - $y = $this->scale->TranslateVertPos($this->texts[$i]->iScalePosY); - $y -= $this->scale->GetVertSpacing()/2; - } - else { - $x = $y = null; - } - $this->texts[$i]->Stroke($this->img,$x,$y); - } - } - } - - // Override inherit method from Graph and give a warning message - function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { - JpGraphError::RaiseL(6005); - //("SetScale() is not meaningfull with Gantt charts."); - } - - // Specify the date range for Gantt graphs (if this is not set it will be - // automtically determined from the input data) - function SetDateRange($aStart,$aEnd) { - // Adjust the start and end so that the indicate the - // begining and end of respective start and end days - if( strpos($aStart,':') === false ) - $aStart = date('Y-m-d 00:00',strtotime($aStart)); - if( strpos($aEnd,':') === false ) - $aEnd = date('Y-m-d 23:59',strtotime($aEnd)); - $this->scale->SetRange($aStart,$aEnd); - } - - // Get the maximum width of the activity titles columns for the bars - // The name is lightly misleading since we from now on can have - // multiple columns in the label section. When this was first written - // it only supported a single label, hence the name. - function GetMaxLabelWidth() { - $m=10; - if( $this->iObj != null ) { - $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin; - $n = count($this->iObj); - for($i=0; $i < $n; ++$i) { - if( !empty($this->iObj[$i]->title) ) { - if( $this->iObj[$i]->title->HasTabs() ) { - list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); - $m=max($m,$tot); - } - else - $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); - } - } - } - return $m; - } - - // Get the maximum height of the titles for the bars - function GetMaxLabelHeight() { - $m=10; - if( $this->iObj != null ) { - $n = count($this->iObj); - // We can not include the title of GnttVLine since that title is stroked at the bottom - // of the Gantt bar and not in the activity title columns - for($i=0; $i < $n; ++$i) { - if( !empty($this->iObj[$i]->title) && !($this->iObj[$i] instanceof GanttVLine) ) { - $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); - } - } - } - return $m; - } - - function GetMaxBarAbsHeight() { - $m=0; - if( $this->iObj != null ) { - $m = $this->iObj[0]->GetAbsHeight($this->img); - $n = count($this->iObj); - for($i=1; $i < $n; ++$i) { - $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); - } - } - return $m; - } - - // Get the maximum used line number (vertical position) for bars - function GetBarMaxLineNumber() { - $m=1; - if( $this->iObj != null ) { - $m = $this->iObj[0]->GetLineNbr(); - $n = count($this->iObj); - for($i=1; $i < $n; ++$i) { - $m=max($m,$this->iObj[$i]->GetLineNbr()); - } - } - return $m; - } - - // Get the minumum and maximum used dates for all bars - function GetBarMinMax() { - $start = 0 ; - $n = count($this->iObj); - while( $start < $n && $this->iObj[$start]->GetMaxDate() === false ) - ++$start; - if( $start >= $n ) { - JpgraphError::RaiseL(6006); - //('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]'); - } - - $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate()); - $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate()); - - for($i=$start+1; $i < $n; ++$i) { - $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate()); - if( $rmax != false ) - $max=Max($max,$rmax); - $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate()); - if( $rmin != false ) - $min=Min($min,$rmin); - } - $minDate = date("Y-m-d",$min); - $min = strtotime($minDate); - $maxDate = date("Y-m-d 23:59",$max); - $max = strtotime($maxDate); - return array($min,$max); - } - - // Create a new auto sized canvas if the user hasn't specified a size - // The size is determined by what scale the user has choosen and hence - // the minimum width needed to display the headers. Some margins are - // also added to make it better looking. - function AutoSize() { - - if( $this->img->img == null ) { - // The predefined left, right, top, bottom margins. - // Note that the top margin might incease depending on - // the title. - $hadj = $vadj = 0; - if( $this->doshadow ) { - $hadj = $this->shadow_width; - $vadj = $this->shadow_width+5; - } - - $lm = $this->img->left_margin; - $rm = $this->img->right_margin +$hadj; - $rm += 2 ; - $tm = $this->img->top_margin; - $bm = $this->img->bottom_margin + $vadj; - $bm += 2; - - // If there are any added GanttVLine we must make sure that the - // bottom margin is wide enough to hold a title. - $n = count($this->iObj); - for($i=0; $i < $n; ++$i) { - if( $this->iObj[$i] instanceof GanttVLine ) { - $bm = max($bm,$this->iObj[$i]->title->GetHeight($this->img)+10); - } - } - - // First find out the height - $n=$this->GetBarMaxLineNumber()+1; - $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); - $height=$n*((1+$this->iLabelVMarginFactor)*$m); - - // Add the height of the scale titles - $h=$this->scale->GetHeaderHeight(); - $height += $h; - - // Calculate the top margin needed for title and subtitle - if( $this->title->t != "" ) { - $tm += $this->title->GetFontHeight($this->img); - } - if( $this->subtitle->t != "" ) { - $tm += $this->subtitle->GetFontHeight($this->img); - } - - // ...and then take the bottom and top plot margins into account - $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; - // Now find the minimum width for the chart required - - // If day scale or smaller is shown then we use the day font width - // as the base size unit. - // If only weeks or above is displayed we use a modified unit to - // get a smaller image. - if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) { - // Add 2 pixel margin on each side - $fw=$this->scale->day->GetFontWidth($this->img)+4; - } - elseif( $this->scale->IsDisplayWeek() ) { - $fw = 8; - } - elseif( $this->scale->IsDisplayMonth() ) { - $fw = 4; - } - else { - $fw = 2; - } - - $nd=$this->scale->GetNumberOfDays(); - - if( $this->scale->IsDisplayDay() ) { - // If the days are displayed we also need to figure out - // how much space each day's title will require. - switch( $this->scale->day->iStyle ) { - case DAYSTYLE_LONG : - $txt = "Monday"; - break; - case DAYSTYLE_LONGDAYDATE1 : - $txt = "Monday 23 Jun"; - break; - case DAYSTYLE_LONGDAYDATE2 : - $txt = "Monday 23 Jun 2003"; - break; - case DAYSTYLE_SHORT : - $txt = "Mon"; - break; - case DAYSTYLE_SHORTDAYDATE1 : - $txt = "Mon 23/6"; - break; - case DAYSTYLE_SHORTDAYDATE2 : - $txt = "Mon 23 Jun"; - break; - case DAYSTYLE_SHORTDAYDATE3 : - $txt = "Mon 23"; - break; - case DAYSTYLE_SHORTDATE1 : - $txt = "23/6"; - break; - case DAYSTYLE_SHORTDATE2 : - $txt = "23 Jun"; - break; - case DAYSTYLE_SHORTDATE3 : - $txt = "Mon 23"; - break; - case DAYSTYLE_SHORTDATE4 : - $txt = "88"; - break; - case DAYSTYLE_CUSTOM : - $txt = date($this->scale->day->iLabelFormStr,strtotime('2003-12-20 18:00')); - break; - case DAYSTYLE_ONELETTER : - default: - $txt = "M"; - break; - } - $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6; - } - - // If we have hours enabled we must make sure that each day has enough - // space to fit the number of hours to be displayed. - if( $this->scale->IsDisplayHour() ) { - // Depending on what format the user has choose we need different amount - // of space. We therefore create a typical string for the choosen format - // and determine the length of that string. - switch( $this->scale->hour->iStyle ) { - case HOURSTYLE_HMAMPM: - $txt = '12:00pm'; - break; - case HOURSTYLE_H24: - // 13 - $txt = '24'; - break; - case HOURSTYLE_HAMPM: - $txt = '12pm'; - break; - case HOURSTYLE_CUSTOM: - $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00')); - break; - case HOURSTYLE_HM24: - default: - $txt = '24:00'; - break; - } - - $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6; - $mw = $hfw; - if( $this->scale->IsDisplayMinute() ) { - // Depending on what format the user has choose we need different amount - // of space. We therefore create a typical string for the choosen format - // and determine the length of that string. - switch( $this->scale->minute->iStyle ) { - case HOURSTYLE_CUSTOM: - $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); - break; - case MINUTESTYLE_MM: - default: - $txt2 = '15'; - break; - } - - $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6; - $n2 = ceil(60 / $this->scale->minute->GetIntervall() ); - $mw = $n2 * $mfw; - } - $hfw = $hfw < $mw ? $mw : $hfw ; - $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) ); - $hw = $n * $hfw; - $fw = $fw < $hw ? $hw : $fw ; - } - - // We need to repeat this code block here as well. - // THIS iS NOT A MISTAKE ! - // We really need it since we need to adjust for minutes both in the case - // where hour scale is shown and when it is not shown. - - if( $this->scale->IsDisplayMinute() ) { - // Depending on what format the user has choose we need different amount - // of space. We therefore create a typical string for the choosen format - // and determine the length of that string. - switch( $this->scale->minute->iStyle ) { - case HOURSTYLE_CUSTOM: - $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); - break; - case MINUTESTYLE_MM: - default: - $txt = '15'; - break; - } - - $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6; - $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) ); - $mw = $n * $mfw; - $fw = $fw < $mw ? $mw : $fw ; - } - - // If we display week we must make sure that 7*$fw is enough - // to fit up to 10 characters of the week font (if the week is enabled) - if( $this->scale->IsDisplayWeek() ) { - // Depending on what format the user has choose we need different amount - // of space - $fsw = strlen($this->scale->week->iLabelFormStr); - if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { - $fsw += 8; - } - elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) { - $fsw += 7; - } - else { - $fsw += 4; - } - - $ww = $fsw*$this->scale->week->GetFontWidth($this->img); - if( 7*$fw < $ww ) { - $fw = ceil($ww/7); - } - } - - if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() && - !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || - $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) { - // If we don't display the individual days we can shrink the - // scale a little bit. This is a little bit pragmatic at the - // moment and should be re-written to take into account - // a) What scales exactly are shown and - // b) what format do they use so we know how wide we need to - // make each scale text space at minimum. - $fw /= 2; - if( !$this->scale->IsDisplayWeek() ) { - $fw /= 1.8; - } - } - - $cw = $this->GetMaxActInfoColWidth() ; - $this->scale->actinfo->SetMinColWidth($cw); - if( $this->img->width <= 0 ) { - // Now determine the width for the activity titles column - - // Firdst find out the maximum width of each object column - $titlewidth = max(max($this->GetMaxLabelWidth(), - $this->scale->tableTitle->GetWidth($this->img)), - $this->scale->actinfo->GetWidth($this->img)); - - // Add the width of the vertivcal divider line - $titlewidth += $this->scale->divider->iWeight*2; - - // Adjust the width by the user specified zoom factor - $fw *= $this->iZoomFactor; - - // Now get the total width taking - // titlewidth, left and rigt margin, dayfont size - // into account - $width = $titlewidth + $nd*$fw + $lm+$rm; - } - else { - $width = $this->img->width; - } - - $width = round($width); - $height = round($height); - // Make a sanity check on image size - if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) { - JpgraphError::RaiseL(6007,$width,$height); - //("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities."); - } - $this->img->CreateImgCanvas($width,$height); - $this->img->SetMargin($lm,$rm,$tm,$bm); - } - } - - // Return an array width the maximum width for each activity - // column. This is used when we autosize the columns where we need - // to find out the maximum width of each column. In order to do that we - // must walk through all the objects, sigh... - function GetMaxActInfoColWidth() { - $n = count($this->iObj); - if( $n == 0 ) return; - $w = array(); - $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin; - - for( $i=0; $i < $n; ++$i ) { - $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m); - $nn = count($tmp); - for( $j=0; $j < $nn; ++$j ) { - if( empty($w[$j]) ) - $w[$j] = $tmp[$j]; - else - $w[$j] = max($w[$j],$tmp[$j]); - } - } - return $w; - } - - // Stroke the gantt chart - function Stroke($aStrokeFileName="") { - - // If the filename is the predefined value = '_csim_special_' - // we assume that the call to stroke only needs to do enough - // to correctly generate the CSIM maps. - // We use this variable to skip things we don't strictly need - // to do to generate the image map to improve performance - // a best we can. Therefor you will see a lot of tests !$_csim in the - // code below. - $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); - - // Should we autoscale dates? - - if( !$this->scale->IsRangeSet() ) { - list($min,$max) = $this->GetBarMinMax(); - $this->scale->SetRange($min,$max); - } - - $this->scale->AdjustStartEndDay(); - - // Check if we should autoscale the image - $this->AutoSize(); - - // Should we start from the top or just spread the bars out even over the - // available height - $this->scale->SetVertLayout($this->iLayout); - if( $this->iLayout == GANTT_FROMTOP ) { - $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); - $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); - } - // If it hasn't been set find out the maximum line number - if( $this->scale->iVertLines == -1 ) - $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; - - $maxwidth=max($this->scale->actinfo->GetWidth($this->img), - max($this->GetMaxLabelWidth(), - $this->scale->tableTitle->GetWidth($this->img))); - - $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor)); - - if( !$_csim ) { - $this->StrokePlotArea(); - if( $this->iIconDepth == DEPTH_BACK ) { - $this->StrokeIcons(); - } - } - - $this->scale->Stroke(); - - if( !$_csim ) { - // Due to a minor off by 1 bug we need to temporarily adjust the margin - $this->img->right_margin--; - $this->StrokePlotBox(); - $this->img->right_margin++; - } - - // Stroke Grid line - $this->hgrid->Stroke($this->img,$this->scale); - - $n = count($this->iObj); - for($i=0; $i < $n; ++$i) { - //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); - $this->iObj[$i]->Stroke($this->img,$this->scale); - } - - $this->StrokeTitles(); - - if( !$_csim ) { - $this->StrokeConstrains(); - $this->footer->Stroke($this->img); - - - if( $this->iIconDepth == DEPTH_FRONT) { - $this->StrokeIcons(); - } - - // Stroke all added user texts - $this->StrokeTexts(); - - // Should we do any final image transformation - if( $this->iImgTrans ) { - if( !class_exists('ImgTrans',false) ) { - require_once('jpgraph_imgtrans.php'); - } - - $tform = new ImgTrans($this->img->img); - $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, - $this->iImgTransDirection,$this->iImgTransHighQ, - $this->iImgTransMinSize,$this->iImgTransFillColor, - $this->iImgTransBorder); - } - - - // If the filename is given as the special "__handle" - // then the image handler is returned and the image is NOT - // streamed back - if( $aStrokeFileName == _IMG_HANDLER ) { - return $this->img->img; - } - else { - // Finally stream the generated picture - $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, - $aStrokeFileName); - } - } - } - - function StrokeConstrains() { - $n = count($this->iObj); - - // Stroke all constrains - for($i=0; $i < $n; ++$i) { - - // Some gantt objects may not have constraints associated with them - // for example we can add IconPlots which doesn't have this property. - if( empty($this->iObj[$i]->constraints) ) continue; - - $numConstrains = count($this->iObj[$i]->constraints); - - for( $k = 0; $k < $numConstrains; $k++ ) { - $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow; - if( $vpos >= 0 ) { - $c1 = $this->iObj[$i]->iConstrainPos; - - // Find out which object is on the target row - $targetobj = -1; - for( $j=0; $j < $n && $targetobj == -1; ++$j ) { - if( $this->iObj[$j]->iVPos == $vpos ) { - $targetobj = $j; - } - } - if( $targetobj == -1 ) { - JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos); - //('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.'); - } - $c2 = $this->iObj[$targetobj]->iConstrainPos; - if( count($c1) == 4 && count($c2 ) == 4) { - switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) { - case CONSTRAIN_ENDSTART: - if( $c1[1] < $c2[1] ) { - $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]); - } - else { - $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]); - } - $link->SetPath(3); - break; - case CONSTRAIN_STARTEND: - if( $c1[1] < $c2[1] ) { - $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]); - } - else { - $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]); - } - $link->SetPath(0); - break; - case CONSTRAIN_ENDEND: - if( $c1[1] < $c2[1] ) { - $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]); - } - else { - $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]); - } - $link->SetPath(1); - break; - case CONSTRAIN_STARTSTART: - if( $c1[1] < $c2[1] ) { - $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]); - } - else { - $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]); - } - $link->SetPath(3); - break; - default: - JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos); - //('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos); - break; - } - - $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor); - $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize, - $this->iObj[$i]->constraints[$k]->iConstrainArrowType); - - $link->Stroke($this->img); - } - } - } - } - } - - function GetCSIMAreas() { - if( !$this->iHasStroked ) - $this->Stroke(_CSIM_SPECIALFILE); - - $csim = $this->title->GetCSIMAreas(); - $csim .= $this->subtitle->GetCSIMAreas(); - $csim .= $this->subsubtitle->GetCSIMAreas(); - - $n = count($this->iObj); - for( $i=$n-1; $i >= 0; --$i ) - $csim .= $this->iObj[$i]->GetCSIMArea(); - return $csim; - } -} - -//=================================================== -// CLASS PredefIcons -// Description: Predefined icons for use with Gantt charts -//=================================================== -define('GICON_WARNINGRED',0); -define('GICON_TEXT',1); -define('GICON_ENDCONS',2); -define('GICON_MAIL',3); -define('GICON_STARTCONS',4); -define('GICON_CALC',5); -define('GICON_MAGNIFIER',6); -define('GICON_LOCK',7); -define('GICON_STOP',8); -define('GICON_WARNINGYELLOW',9); -define('GICON_FOLDEROPEN',10); -define('GICON_FOLDER',11); -define('GICON_TEXTIMPORTANT',12); - -class PredefIcons { - private $iBuiltinIcon = null, $iLen = -1 ; - - function GetLen() { - return $this->iLen ; - } - - function GetImg($aIdx) { - if( $aIdx < 0 || $aIdx >= $this->iLen ) { - JpGraphError::RaiseL(6010,$aIdx); - //('Illegal icon index for Gantt builtin icon ['.$aIdx.']'); - } - return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1])); - } - - function __construct() { - //========================================================== - // warning.png - //========================================================== - $this->iBuiltinIcon[0][0]= 1043 ; - $this->iBuiltinIcon[0][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. - 'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'. - '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'. - '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'. - 'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'. - 'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'. - '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'. - 'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'. - 'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'. - 'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'. - 'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'. - 'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'. - 'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'. - 'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ; - - //========================================================== - // edit.png - //========================================================== - $this->iBuiltinIcon[1][0]= 959 ; - $this->iBuiltinIcon[1][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'. - 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'. - 'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'. - 'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'. - 'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'. - 'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'. - 'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'. - 'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'. - 'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'. - 'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'. - 'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'. - 'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'. - 'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ; - - //========================================================== - // endconstrain.png - //========================================================== - $this->iBuiltinIcon[2][0]= 666 ; - $this->iBuiltinIcon[2][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. - 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'. - 'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'. - 'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'. - 'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'. - '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'. - '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'. - 'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'. - 'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ; - - //========================================================== - // mail.png - //========================================================== - $this->iBuiltinIcon[3][0]= 1122 ; - $this->iBuiltinIcon[3][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. - 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'. - 'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'. - 'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'. - 'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'. - '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'. - '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'. - 'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'. - 'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'. - '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'. - 'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'. - 'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'. - 'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'. - 'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'. - 'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ; - - //========================================================== - // startconstrain.png - //========================================================== - $this->iBuiltinIcon[4][0]= 725 ; - $this->iBuiltinIcon[4][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. - 'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'. - 'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'. - 'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'. - 'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'. - '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'. - 'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'. - 'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'. - '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'. - 'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ; - - //========================================================== - // calc.png - //========================================================== - $this->iBuiltinIcon[5][0]= 589 ; - $this->iBuiltinIcon[5][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'. - 'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'. - 'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'. - '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'. - 'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'. - 'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'. - 'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'. - 'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ; - - //========================================================== - // mag.png - //========================================================== - $this->iBuiltinIcon[6][0]= 1415 ; - $this->iBuiltinIcon[6][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. - 'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'. - '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'. - 'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'. - 'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'. - 'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'. - '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'. - 'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'. - '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'. - 'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'. - 'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'. - 'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'. - 'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'. - 'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'. - 'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'. - 'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'. - 'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'. - 'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'. - 'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ; - - //========================================================== - // lock.png - //========================================================== - $this->iBuiltinIcon[7][0]= 963 ; - $this->iBuiltinIcon[7][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. - 'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'. - 'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'. - 'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'. - 'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'. - 'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'. - 'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'. - 'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'. - 'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'. - 'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'. - 'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'. - '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'. - 'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ; - - //========================================================== - // stop.png - //========================================================== - $this->iBuiltinIcon[8][0]= 889 ; - $this->iBuiltinIcon[8][1]= - 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. - 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'. - 'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'. - 'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'. - 'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'. - 'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'. - 'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'. - 'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'. - 'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'. - 'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'. - 'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'. - 'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ; - - //========================================================== - // error.png - //========================================================== - $this->iBuiltinIcon[9][0]= 541 ; - $this->iBuiltinIcon[9][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. - 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. - 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'. - '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'. - 'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'. - 'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'. - 'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'. - 'iOsCHgAAAABJRU5ErkJggg==' ; - - //========================================================== - // openfolder.png - //========================================================== - $this->iBuiltinIcon[10][0]= 2040 ; - $this->iBuiltinIcon[10][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'. - 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'. - 'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'. - 'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'. - 'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'. - 'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'. - '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'. - 'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'. - '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'. - 'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'. - 'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'. - 'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'. - 'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'. - 'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'. - 'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'. - 'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'. - 'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'. - 'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'. - 'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'. - 'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'. - 'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'. - 'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'. - 'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'. - 'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'. - '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'. - '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'. - 'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'. - 'dBntAAAAAElFTkSuQmCC' ; - - //========================================================== - // folder.png - //========================================================== - $this->iBuiltinIcon[11][0]= 1824 ; - $this->iBuiltinIcon[11][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. - 'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'. - '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'. - 'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'. - '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'. - 'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'. - 'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'. - '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'. - 'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'. - 'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'. - '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'. - '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'. - 'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'. - 'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'. - 'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'. - 'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'. - 'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'. - 'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'. - 'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'. - 'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'. - 'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'. - 'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'. - 'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'. - 'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'. - 'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ; - - //========================================================== - // file_important.png - //========================================================== - $this->iBuiltinIcon[12][0]= 1785 ; - $this->iBuiltinIcon[12][1]= - 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. - 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'. - 'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'. - 'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'. - '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'. - 's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'. - 'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'. - 'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'. - 'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'. - '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'. - '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'. - 'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'. - 'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'. - 'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'. - 'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'. - 't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'. - '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'. - 'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'. - 'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'. - 'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'. - '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'. - 'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'. - 'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'. - '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ; - - $this->iLen = count($this->iBuiltinIcon); - } -} - -//=================================================== -// Global cache for builtin images -//=================================================== -$_gPredefIcons = new PredefIcons(); - -//=================================================== -// CLASS IconImage -// Description: Holds properties for an icon image -//=================================================== -class IconImage { - private $iGDImage=null; - private $iWidth,$iHeight; - private $ixalign='left',$iyalign='center'; - private $iScale=1.0; - - function __construct($aIcon,$aScale=1) { - GLOBAL $_gPredefIcons ; - if( is_string($aIcon) ) { - $this->iGDImage = Graph::LoadBkgImage('',$aIcon); - } - elseif( is_integer($aIcon) ) { - // Builtin image - $this->iGDImage = $_gPredefIcons->GetImg($aIcon); - } - else { - JpGraphError::RaiseL(6011); - //('Argument to IconImage must be string or integer'); - } - $this->iScale = $aScale; - $this->iWidth = Image::GetWidth($this->iGDImage); - $this->iHeight = Image::GetHeight($this->iGDImage); - } - - function GetWidth() { - return round($this->iScale*$this->iWidth); - } - - function GetHeight() { - return round($this->iScale*$this->iHeight); - } - - function SetAlign($aX='left',$aY='center') { - $this->ixalign = $aX; - $this->iyalign = $aY; - } - - function Stroke($aImg,$x,$y) { - - if( $this->ixalign == 'right' ) { - $x -= $this->iWidth; - } - elseif( $this->ixalign == 'center' ) { - $x -= round($this->iWidth/2*$this->iScale); - } - - if( $this->iyalign == 'bottom' ) { - $y -= $this->iHeight; - } - elseif( $this->iyalign == 'center' ) { - $y -= round($this->iHeight/2*$this->iScale); - } - - $aImg->Copy($this->iGDImage, - $x,$y,0,0, - round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale), - $this->iWidth,$this->iHeight); - } -} - - -//=================================================== -// CLASS TextProperty -// Description: Holds properties for a text -//=================================================== -class TextProperty { - public $iShow=true; - public $csimtarget='',$csimwintarget='',$csimalt=''; - private $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; - private $iFontArray=array(); - private $iColor="black"; - private $iText=""; - private $iHAlign="left",$iVAlign="bottom"; - - //--------------- - // CONSTRUCTOR - function __construct($aTxt='') { - $this->iText = $aTxt; - } - - //--------------- - // PUBLIC METHODS - function Set($aTxt) { - $this->iText = $aTxt; - } - - function SetCSIMTarget($aTarget,$aAltText='',$aWinTarget='') { - if( is_string($aTarget) ) - $aTarget = array($aTarget); - $this->csimtarget=$aTarget; - - if( is_string($aWinTarget) ) - $aWinTarget = array($aWinTarget); - $this->csimwintarget=$aWinTarget; - - if( is_string($aAltText) ) - $aAltText = array($aAltText); - $this->csimalt=$aAltText; - - } - - function SetCSIMAlt($aAltText) { - if( is_string($aAltText) ) - $aAltText = array($aAltText); - $this->csimalt=$aAltText; - } - - // Set text color - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function HasTabs() { - if( is_string($this->iText) ) { - return substr_count($this->iText,"\t") > 0; - } - elseif( is_array($this->iText) ) { - return false; - } - } - - // Get number of tabs in string - function GetNbrTabs() { - if( is_string($this->iText) ) { - return substr_count($this->iText,"\t") ; - } - else{ - return 0; - } - } - - // Set alignment - function Align($aHAlign,$aVAlign="bottom") { - $this->iHAlign=$aHAlign; - $this->iVAlign=$aVAlign; - } - - // Synonym - function SetAlign($aHAlign,$aVAlign="bottom") { - $this->iHAlign=$aHAlign; - $this->iVAlign=$aVAlign; - } - - // Specify font - function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { - $this->iFFamily = $aFFamily; - $this->iFStyle = $aFStyle; - $this->iFSize = $aFSize; - } - - function SetColumnFonts($aFontArray) { - if( !is_array($aFontArray) || count($aFontArray[0]) != 3 ) { - JpGraphError::RaiseL(6033); - // 'Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)' - } - $this->iFontArray = $aFontArray; - } - - - function IsColumns() { - return is_array($this->iText) ; - } - - // Get width of text. If text contains several columns separated by - // tabs then return both the total width as well as an array with a - // width for each column. - function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { - $extra_margin=4; - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - if( is_string($this->iText) ) { - if( strlen($this->iText) == 0 ) return 0; - $tmp = preg_split('/\t/',$this->iText); - if( count($tmp) <= 1 || !$aUseTabs ) { - $w = $aImg->GetTextWidth($this->iText); - return $w + 2*$extra_margin; - } - else { - $tot=0; - $n = count($tmp); - for($i=0; $i < $n; ++$i) { - $res[$i] = $aImg->GetTextWidth($tmp[$i]); - $tot += $res[$i]*$aTabExtraMargin; - } - return array(round($tot),$res); - } - } - elseif( is_object($this->iText) ) { - // A single icon - return $this->iText->GetWidth()+2*$extra_margin; - } - elseif( is_array($this->iText) ) { - // Must be an array of texts. In this case we return the sum of the - // length + a fixed margin of 4 pixels on each text string - $n = count($this->iText); - $nf = count($this->iFontArray); - for( $i=0, $w=0; $i < $n; ++$i ) { - if( $i < $nf ) { - $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); - } - else { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - } - $tmp = $this->iText[$i]; - if( is_string($tmp) ) { - $w += $aImg->GetTextWidth($tmp)+$extra_margin; - } - else { - if( is_object($tmp) === false ) { - JpGraphError::RaiseL(6012); - } - $w += $tmp->GetWidth()+$extra_margin; - } - } - return $w; - } - else { - JpGraphError::RaiseL(6012); - } - } - - // for the case where we have multiple columns this function returns the width of each - // column individually. If there is no columns just return the width of the single - // column as an array of one - function GetColWidth($aImg,$aMargin=0) { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - if( is_array($this->iText) ) { - $n = count($this->iText); - $nf = count($this->iFontArray); - for( $i=0, $w=array(); $i < $n; ++$i ) { - $tmp = $this->iText[$i]; - if( is_string($tmp) ) { - if( $i < $nf ) { - $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); - } - else { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - } - $w[$i] = $aImg->GetTextWidth($tmp)+$aMargin; - } - else { - if( is_object($tmp) === false ) { - JpGraphError::RaiseL(6012); - } - $w[$i] = $tmp->GetWidth()+$aMargin; - } - } - return $w; - } - else { - return array($this->GetWidth($aImg)); - } - } - - // Get total height of text - function GetHeight($aImg) { - $nf = count($this->iFontArray); - $maxheight = -1; - - if( $nf > 0 ) { - // We have to find out the largest font and take that one as the - // height of the row - for($i=0; $i < $nf; ++$i ) { - $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); - $height = $aImg->GetFontHeight(); - $maxheight = max($height,$maxheight); - } - } - - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - $height = $aImg->GetFontHeight(); - $maxheight = max($height,$maxheight); - return $maxheight; - } - - // Unhide/hide the text - function Show($aShow=true) { - $this->iShow=$aShow; - } - - // Stroke text at (x,y) coordinates. If the text contains tabs then the - // x parameter should be an array of positions to be used for each successive - // tab mark. If no array is supplied then the tabs will be ignored. - function Stroke($aImg,$aX,$aY) { - if( $this->iShow ) { - $aImg->SetColor($this->iColor); - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); - if( $this->GetNbrTabs() < 1 ) { - if( is_string($this->iText) ) { - if( is_array($aX) ) $aX=$aX[0]; - if( is_array($aY) ) $aY=$aY[0]; - $aImg->StrokeText($aX,$aY,$this->iText); - } - elseif( is_array($this->iText) && ($n = count($this->iText)) > 0 ) { - $ax = is_array($aX) ; - $ay = is_array($aY) ; - if( $ax && $ay ) { - // Nothing; both are already arrays - } - elseif( $ax ) { - $aY = array_fill(0,$n,$aY); - } - elseif( $ay ) { - $aX = array_fill(0,$n,$aX); - } - else { - $aX = array_fill(0,$n,$aX); - $aY = array_fill(0,$n,$aY); - } - $n = min($n, count($aX) ) ; - $n = min($n, count($aY) ) ; - for($i=0; $i < $n; ++$i ) { - $tmp = $this->iText[$i]; - if( is_object($tmp) ) { - $tmp->Stroke($aImg,$aX[$i],$aY[$i]); - } - else { - if( $i < count($this->iFontArray) ) { - $font = $this->iFontArray[$i]; - $aImg->SetFont($font[0],$font[1],$font[2]); - } - else { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - } - $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp)); - } - } - } - } - else { - $tmp = preg_split('/\t/',$this->iText); - $n = min(count($tmp),count($aX)); - for($i=0; $i < $n; ++$i) { - if( $i < count($this->iFontArray) ) { - $font = $this->iFontArray[$i]; - $aImg->SetFont($font[0],$font[1],$font[2]); - } - else { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - } - $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); - } - } - } - } -} - -//=================================================== -// CLASS HeaderProperty -// Description: Data encapsulating class to hold property -// for each type of the scale headers -//=================================================== -class HeaderProperty { - public $grid; - public $iShowLabels=true,$iShowGrid=true; - public $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; - public $iStyle=0; - public $iFrameColor="black",$iFrameWeight=1; - public $iBackgroundColor="white"; - public $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale - public $iTextColor="black"; - public $iLabelFormStr="%d"; - public $iIntervall = 1; - - //--------------- - // CONSTRUCTOR - function __construct() { - $this->grid = new LineProperty(); - } - - //--------------- - // PUBLIC METHODS - function Show($aShow=true) { - $this->iShowLabels = $aShow; - } - - function SetIntervall($aInt) { - $this->iIntervall = $aInt; - } - - function SetInterval($aInt) { - $this->iIntervall = $aInt; - } - - function GetIntervall() { - return $this->iIntervall ; - } - - function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { - $this->iFFamily = $aFFamily; - $this->iFStyle = $aFStyle; - $this->iFSize = $aFSize; - } - - function SetFontColor($aColor) { - $this->iTextColor = $aColor; - } - - function GetFontHeight($aImg) { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - return $aImg->GetFontHeight(); - } - - function GetFontWidth($aImg) { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - return $aImg->GetFontWidth(); - } - - function GetStrWidth($aImg,$aStr) { - $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); - return $aImg->GetTextWidth($aStr); - } - - function SetStyle($aStyle) { - $this->iStyle = $aStyle; - } - - function SetBackgroundColor($aColor) { - $this->iBackgroundColor=$aColor; - } - - function SetFrameWeight($aWeight) { - $this->iFrameWeight=$aWeight; - } - - function SetFrameColor($aColor) { - $this->iFrameColor=$aColor; - } - - // Only used by day scale - function SetWeekendColor($aColor) { - $this->iWeekendBackgroundColor=$aColor; - } - - // Only used by day scale - function SetSundayFontColor($aColor) { - $this->iSundayTextColor=$aColor; - } - - function SetTitleVertMargin($aMargin) { - $this->iTitleVertMargin=$aMargin; - } - - function SetLabelFormatString($aStr) { - $this->iLabelFormStr=$aStr; - } - - function SetFormatString($aStr) { - $this->SetLabelFormatString($aStr); - } - - -} - -//=================================================== -// CLASS GanttScale -// Description: Responsible for calculating and showing -// the scale in a gantt chart. This includes providing methods for -// converting dates to position in the chart as well as stroking the -// date headers (days, week, etc). -//=================================================== -class GanttScale { - public $minute,$hour,$day,$week,$month,$year; - public $divider,$dividerh,$tableTitle; - public $iStartDate=-1,$iEndDate=-1; - // Number of gantt bar position (n.b not necessariliy the same as the number of bars) - // we could have on bar in position 1, and one bar in position 5 then there are two - // bars but the number of bar positions is 5 - public $actinfo; - public $iTopPlotMargin=10,$iBottomPlotMargin=15; - public $iVertLines=-1; - public $iVertHeaderSize=-1; - // The width of the labels (defaults to the widest of all labels) - private $iLabelWidth; - // Out image to stroke the scale to - private $iImg; - private $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; - private $iTableHeaderFrameWeight=1; - private $iAvailableHeight=-1,$iVertSpacing=-1; - private $iDateLocale; - private $iVertLayout=GANTT_EVEN; - private $iUsePlotWeekendBackground=true; - private $iWeekStart = 1; // Default to have weekends start on Monday - - //--------------- - // CONSTRUCTOR - function __construct($aImg) { - $this->iImg = $aImg; - $this->iDateLocale = new DateLocale(); - - $this->minute = new HeaderProperty(); - $this->minute->SetIntervall(15); - $this->minute->SetLabelFormatString('i'); - $this->minute->SetFont(FF_FONT0); - $this->minute->grid->SetColor("gray"); - - $this->hour = new HeaderProperty(); - $this->hour->SetFont(FF_FONT0); - $this->hour->SetIntervall(6); - $this->hour->SetStyle(HOURSTYLE_HM24); - $this->hour->SetLabelFormatString('H:i'); - $this->hour->grid->SetColor("gray"); - - $this->day = new HeaderProperty(); - $this->day->grid->SetColor("gray"); - $this->day->SetLabelFormatString('l'); - - $this->week = new HeaderProperty(); - $this->week->SetLabelFormatString("w%d"); - $this->week->SetFont(FF_FONT1); - - $this->month = new HeaderProperty(); - $this->month->SetFont(FF_FONT1,FS_BOLD); - - $this->year = new HeaderProperty(); - $this->year->SetFont(FF_FONT1,FS_BOLD); - - $this->divider=new LineProperty(); - $this->dividerh=new LineProperty(); - $this->dividerh->SetWeight(2); - $this->divider->SetWeight(6); - $this->divider->SetColor('gray'); - $this->divider->SetStyle('fancy'); - - $this->tableTitle=new TextProperty(); - $this->tableTitle->Show(false); - $this->actinfo = new GanttActivityInfo(); - } - - //--------------- - // PUBLIC METHODS - // Specify what headers should be visible - function ShowHeaders($aFlg) { - $this->day->Show($aFlg & GANTT_HDAY); - $this->week->Show($aFlg & GANTT_HWEEK); - $this->month->Show($aFlg & GANTT_HMONTH); - $this->year->Show($aFlg & GANTT_HYEAR); - $this->hour->Show($aFlg & GANTT_HHOUR); - $this->minute->Show($aFlg & GANTT_HMIN); - - // Make some default settings of gridlines whihc makes sense - if( $aFlg & GANTT_HWEEK ) { - $this->month->grid->Show(false); - $this->year->grid->Show(false); - } - if( $aFlg & GANTT_HHOUR ) { - $this->day->grid->SetColor("black"); - } - } - - // Should the weekend background stretch all the way down in the plotarea - function UseWeekendBackground($aShow) { - $this->iUsePlotWeekendBackground = $aShow; - } - - // Have a range been specified? - function IsRangeSet() { - return $this->iStartDate!=-1 && $this->iEndDate!=-1; - } - - // Should the layout be from top or even? - function SetVertLayout($aLayout) { - $this->iVertLayout = $aLayout; - } - - // Which locale should be used? - function SetDateLocale($aLocale) { - $this->iDateLocale->Set($aLocale); - } - - // Number of days we are showing - function GetNumberOfDays() { - return round(($this->iEndDate-$this->iStartDate)/SECPERDAY); - } - - // The width of the actual plot area - function GetPlotWidth() { - $img=$this->iImg; - return $img->width - $img->left_margin - $img->right_margin; - } - - // Specify the width of the titles(labels) for the activities - // (This is by default set to the minimum width enought for the - // widest title) - function SetLabelWidth($aLabelWidth) { - $this->iLabelWidth=$aLabelWidth; - } - - // Which day should the week start? - // 0==Sun, 1==Monday, 2==Tuesday etc - function SetWeekStart($aStartDay) { - $this->iWeekStart = $aStartDay % 7; - - //Recalculate the startday since this will change the week start - $this->SetRange($this->iStartDate,$this->iEndDate); - } - - // Do we show min scale? - function IsDisplayMinute() { - return $this->minute->iShowLabels; - } - - // Do we show day scale? - function IsDisplayHour() { - return $this->hour->iShowLabels; - } - - - // Do we show day scale? - function IsDisplayDay() { - return $this->day->iShowLabels; - } - - // Do we show week scale? - function IsDisplayWeek() { - return $this->week->iShowLabels; - } - - // Do we show month scale? - function IsDisplayMonth() { - return $this->month->iShowLabels; - } - - // Do we show year scale? - function IsDisplayYear() { - return $this->year->iShowLabels; - } - - // Specify spacing (in percent of bar height) between activity bars - function SetVertSpacing($aSpacing) { - $this->iVertSpacing = $aSpacing; - } - - // Specify scale min and max date either as timestamp or as date strings - // Always round to the nearest week boundary - function SetRange($aMin,$aMax) { - $this->iStartDate = $this->NormalizeDate($aMin); - $this->iEndDate = $this->NormalizeDate($aMax); - } - - - // Adjust the start and end date so they fit to beginning/ending - // of the week taking the specified week start day into account. - function AdjustStartEndDay() { - - if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) { - // Don't adjust - return; - } - - // Get day in week for start and ending date (Sun==0) - $ds=strftime("%w",$this->iStartDate); - $de=strftime("%w",$this->iEndDate); - - // We want to start on iWeekStart day. But first we subtract a week - // if the startdate is "behind" the day the week start at. - // This way we ensure that the given start date is always included - // in the range. If we don't do this the nearest correct weekday in the week - // to start at might be later than the start date. - if( $ds < $this->iWeekStart ) - $d = strtotime('-7 day',$this->iStartDate); - else - $d = $this->iStartDate; - $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ ); - $this->iStartDate = $adjdate; - - // We want to end on the last day of the week - $preferredEndDay = ($this->iWeekStart+6)%7; - if( $preferredEndDay != $de ) { - // Solve equivalence eq: $de + x ~ $preferredDay (mod 7) - $adj = (7+($preferredEndDay - $de)) % 7; - $adjdate = strtotime("+$adj day",$this->iEndDate); - $this->iEndDate = $adjdate; - } - } - - // Specify background for the table title area (upper left corner of the table) - function SetTableTitleBackground($aColor) { - $this->iTableHeaderBackgroundColor = $aColor; - } - - /////////////////////////////////////// - // PRIVATE Methods - - // Determine the height of all the scale headers combined - function GetHeaderHeight() { - $img=$this->iImg; - $height=1; - if( $this->minute->iShowLabels ) { - $height += $this->minute->GetFontHeight($img); - $height += $this->minute->iTitleVertMargin; - } - if( $this->hour->iShowLabels ) { - $height += $this->hour->GetFontHeight($img); - $height += $this->hour->iTitleVertMargin; - } - if( $this->day->iShowLabels ) { - $height += $this->day->GetFontHeight($img); - $height += $this->day->iTitleVertMargin; - } - if( $this->week->iShowLabels ) { - $height += $this->week->GetFontHeight($img); - $height += $this->week->iTitleVertMargin; - } - if( $this->month->iShowLabels ) { - $height += $this->month->GetFontHeight($img); - $height += $this->month->iTitleVertMargin; - } - if( $this->year->iShowLabels ) { - $height += $this->year->GetFontHeight($img); - $height += $this->year->iTitleVertMargin; - } - return $height; - } - - // Get width (in pixels) for a single day - function GetDayWidth() { - return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); - } - - // Get width (in pixels) for a single hour - function GetHourWidth() { - return $this->GetDayWidth() / 24 ; - } - - function GetMinuteWidth() { - return $this->GetHourWidth() / 60 ; - } - - // Nuber of days in a year - function GetNumDaysInYear($aYear) { - if( $this->IsLeap($aYear) ) - return 366; - else - return 365; - } - - // Get week number - function GetWeekNbr($aDate,$aSunStart=true) { - // We can't use the internal strftime() since it gets the weeknumber - // wrong since it doesn't follow ISO on all systems since this is - // system linrary dependent. - // Even worse is that this works differently if we are on a Windows - // or UNIX box (it even differs between UNIX boxes how strftime() - // is natively implemented) - // - // Credit to Nicolas Hoizey for this elegant - // version of Week Nbr calculation. - - $day = $this->NormalizeDate($aDate); - if( $aSunStart ) - $day += 60*60*24; - - /*------------------------------------------------------------------------- - According to ISO-8601 : - "Week 01 of a year is per definition the first week that has the Thursday in this year, - which is equivalent to the week that contains the fourth day of January. - In other words, the first week of a new year is the week that has the majority of its - days in the new year." - - Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! - - day of year = date("z", $day) + 1 - offset to thursday = 3 - (date("w", $day) + 6) % 7 - first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 - week number = (thursday's day of year - first thursday's day of year) / 7 + 1 - ---------------------------------------------------------------------------*/ - - $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday - $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; - - return $week; - } - - // Is year a leap year? - function IsLeap($aYear) { - // Is the year a leap year? - //$year = 0+date("Y",$aDate); - if( $aYear % 4 == 0) - if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) - return true; - return false; - } - - // Get current year - function GetYear($aDate) { - return 0+Date("Y",$aDate); - } - - // Return number of days in a year - function GetNumDaysInMonth($aMonth,$aYear) { - $days=array(31,28,31,30,31,30,31,31,30,31,30,31); - $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); - if( $this->IsLeap($aYear)) - return $daysl[$aMonth]; - else - return $days[$aMonth]; - } - - // Get day in month - function GetMonthDayNbr($aDate) { - return 0+strftime("%d",$aDate); - } - - // Get day in year - function GetYearDayNbr($aDate) { - return 0+strftime("%j",$aDate); - } - - // Get month number - function GetMonthNbr($aDate) { - return 0+strftime("%m",$aDate); - } - - // Translate a date to screen coordinates (horizontal scale) - function TranslateDate($aDate) { - // - // In order to handle the problem with Daylight savings time - // the scale written with equal number of seconds per day beginning - // with the start date. This means that we "cement" the state of - // DST as it is in the start date. If later the scale includes the - // switchover date (depends on the locale) we need to adjust back - // if the date we try to translate has a different DST status since - // we would otherwise be off by one hour. - $aDate = $this->NormalizeDate($aDate); - $tmp = localtime($aDate); - $cloc = $tmp[8]; - $tmp = localtime($this->iStartDate); - $sloc = $tmp[8]; - $offset = 0; - if( $sloc != $cloc) { - if( $sloc ) - $offset = 3600; - else - $offset = -3600; - } - $img=$this->iImg; - return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; - } - - // Get screen coordinatesz for the vertical position for a bar - function TranslateVertPos($aPos,$atTop=false) { - $img=$this->iImg; - if( $aPos > $this->iVertLines ) - JpGraphError::RaiseL(6015,$aPos); - // 'Illegal vertical position %d' - if( $this->iVertLayout == GANTT_EVEN ) { - // Position the top bar at 1 vert spacing from the scale - $pos = round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); - } - else { - // position the top bar at 1/2 a vert spacing from the scale - $pos = round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); - } - - if( $atTop ) - $pos -= $this->iVertSpacing; - - return $pos; - } - - // What is the vertical spacing? - function GetVertSpacing() { - return $this->iVertSpacing; - } - - // Convert a date to timestamp - function NormalizeDate($aDate) { - if( $aDate === false ) return false; - if( is_string($aDate) ) { - $t = strtotime($aDate); - if( $t === FALSE || $t === -1 ) { - JpGraphError::RaiseL(6016,$aDate); - //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30"); - } - return $t; - } - elseif( is_int($aDate) || is_float($aDate) ) - return $aDate; - else - JpGraphError::RaiseL(6017,$aDate); - //Unknown date format in GanttScale ($aDate)."); - } - - - // Convert a time string to minutes - - function TimeToMinutes($aTimeString) { - // Split in hours and minutes - $pos=strpos($aTimeString,':'); - $minint=60; - if( $pos === false ) { - $hourint = $aTimeString; - $minint = 0; - } - else { - $hourint = floor(substr($aTimeString,0,$pos)); - $minint = floor(substr($aTimeString,$pos+1)); - } - $minint += 60 * $hourint; - return $minint; - } - - // Stroke the day scale (including gridlines) - function StrokeMinutes($aYCoord,$getHeight=false) { - $img=$this->iImg; - $xt=$img->left_margin+$this->iLabelWidth; - $yt=$aYCoord+$img->top_margin; - if( $this->minute->iShowLabels ) { - $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize); - $yb = $yt + $img->GetFontHeight() + - $this->minute->iTitleVertMargin + $this->minute->iFrameWeight; - if( $getHeight ) { - return $yb - $img->top_margin; - } - $xb = $img->width-$img->right_margin+1; - $img->SetColor($this->minute->iBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - - $x = $xt; - $img->SetTextAlign("center"); - $day = date('w',$this->iStartDate); - $minint = $this->minute->GetIntervall() ; - - if( 60 % $minint !== 0 ) { - JpGraphError::RaiseL(6018,$minint); - //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.'); - } - - - $n = 60 / $minint; - $datestamp = $this->iStartDate; - $width = $this->GetHourWidth() / $n ; - if( $width < 8 ) { - // TO small width to draw minute scale - JpGraphError::RaiseL(6019,$width); - //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.'); - } - - $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) ); - $nd = $this->GetNumberOfDays(); - // Convert to intervall to seconds - $minint *= 60; - for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) { - for( $k=0; $k < $nh; ++$k ) { - for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) { - if( $day==6 || $day==0 ) { - - $img->PushColor($this->day->iWeekendBackgroundColor); - if( $this->iUsePlotWeekendBackground ) - $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); - else - $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); - $img->PopColor(); - - } - - if( $day==0 ) - $img->SetColor($this->day->iSundayTextColor); - else - $img->SetColor($this->day->iTextColor); - - switch( $this->minute->iStyle ) { - case MINUTESTYLE_CUSTOM: - $txt = date($this->minute->iLabelFormStr,$datestamp); - break; - case MINUTESTYLE_MM: - default: - // 15 - $txt = date('i',$datestamp); - break; - } - $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt); - - // Fix a rounding problem the wrong way .. - // If we also have hour scale then don't draw the firsta or last - // gridline since that will be overwritten by the hour scale gridline if such exists. - // However, due to the propagation of rounding of the 'x+=width' term in the loop - // this might sometimes be one pixel of so we fix this by not drawing it. - // The proper way to fix it would be to re-calculate the scale for each step and - // not using the additive term. - if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) { - $img->SetColor($this->minute->grid->iColor); - $img->SetLineWeight($this->minute->grid->iWeight); - $img->Line($x,$yt,$x,$yb); - $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); - } - } - } - } - $img->SetColor($this->minute->iFrameColor); - $img->SetLineWeight($this->minute->iFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - return $yb - $img->top_margin; - } - return $aYCoord; - } - - // Stroke the day scale (including gridlines) - function StrokeHours($aYCoord,$getHeight=false) { - $img=$this->iImg; - $xt=$img->left_margin+$this->iLabelWidth; - $yt=$aYCoord+$img->top_margin; - if( $this->hour->iShowLabels ) { - $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize); - $yb = $yt + $img->GetFontHeight() + - $this->hour->iTitleVertMargin + $this->hour->iFrameWeight; - if( $getHeight ) { - return $yb - $img->top_margin; - } - $xb = $img->width-$img->right_margin+1; - $img->SetColor($this->hour->iBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - - $x = $xt; - $img->SetTextAlign("center"); - $tmp = $this->hour->GetIntervall() ; - $minint = $this->TimeToMinutes($tmp); - if( 1440 % $minint !== 0 ) { - JpGraphError::RaiseL(6020,$tmp); - //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp); - } - - $n = ceil(24*60 / $minint ); - $datestamp = $this->iStartDate; - $day = date('w',$this->iStartDate); - $doback = !$this->minute->iShowLabels; - $width = $this->GetDayWidth() / $n ; - for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) { - for($i=0; $i < $n ;++$i, $x+=$width) { - if( $day==6 || $day==0 ) { - - $img->PushColor($this->day->iWeekendBackgroundColor); - if( $this->iUsePlotWeekendBackground && $doback ) - $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); - else - $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); - $img->PopColor(); - - } - - if( $day==0 ) - $img->SetColor($this->day->iSundayTextColor); - else - $img->SetColor($this->day->iTextColor); - - switch( $this->hour->iStyle ) { - case HOURSTYLE_HMAMPM: - // 1:35pm - $txt = date('g:ia',$datestamp); - break; - case HOURSTYLE_H24: - // 13 - $txt = date('H',$datestamp); - break; - case HOURSTYLE_HAMPM: - $txt = date('ga',$datestamp); - break; - case HOURSTYLE_CUSTOM: - $txt = date($this->hour->iLabelFormStr,$datestamp); - break; - case HOURSTYLE_HM24: - default: - $txt = date('H:i',$datestamp); - break; - } - $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt); - $img->SetColor($this->hour->grid->iColor); - $img->SetLineWeight($this->hour->grid->iWeight); - $img->Line($x,$yt,$x,$yb); - $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); - //$datestamp += $minint*60 - $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0, - date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); - - } - } - $img->SetColor($this->hour->iFrameColor); - $img->SetLineWeight($this->hour->iFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - return $yb - $img->top_margin; - } - return $aYCoord; - } - - - // Stroke the day scale (including gridlines) - function StrokeDays($aYCoord,$getHeight=false) { - $img=$this->iImg; - $daywidth=$this->GetDayWidth(); - $xt=$img->left_margin+$this->iLabelWidth; - $yt=$aYCoord+$img->top_margin; - if( $this->day->iShowLabels ) { - $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); - $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; - if( $getHeight ) { - return $yb - $img->top_margin; - } - $xb=$img->width-$img->right_margin+1; - $img->SetColor($this->day->iBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - - $x = $xt; - $img->SetTextAlign("center"); - $day = date('w',$this->iStartDate); - $datestamp = $this->iStartDate; - - $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels); - - setlocale(LC_TIME,$this->iDateLocale->iLocale); - - for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) { - if( $day==6 || $day==0 ) { - $img->SetColor($this->day->iWeekendBackgroundColor); - if( $this->iUsePlotWeekendBackground && $doback) - $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, - $x+$daywidth,$img->height-$img->bottom_margin); - else - $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, - $x+$daywidth,$yb-$this->day->iFrameWeight); - } - - $mn = strftime('%m',$datestamp); - if( $mn[0]=='0' ) - $mn = $mn[1]; - - switch( $this->day->iStyle ) { - case DAYSTYLE_LONG: - // "Monday" - $txt = strftime('%A',$datestamp); - break; - case DAYSTYLE_SHORT: - // "Mon" - $txt = strftime('%a',$datestamp); - break; - case DAYSTYLE_SHORTDAYDATE1: - // "Mon 23/6" - $txt = strftime('%a %d/'.$mn,$datestamp); - break; - case DAYSTYLE_SHORTDAYDATE2: - // "Mon 23 Jun" - $txt = strftime('%a %d %b',$datestamp); - break; - case DAYSTYLE_SHORTDAYDATE3: - // "Mon 23 Jun 2003" - $txt = strftime('%a %d %b %Y',$datestamp); - break; - case DAYSTYLE_LONGDAYDATE1: - // "Monday 23 Jun" - $txt = strftime('%A %d %b',$datestamp); - break; - case DAYSTYLE_LONGDAYDATE2: - // "Monday 23 Jun 2003" - $txt = strftime('%A %d %b %Y',$datestamp); - break; - case DAYSTYLE_SHORTDATE1: - // "23/6" - $txt = strftime('%d/'.$mn,$datestamp); - break; - case DAYSTYLE_SHORTDATE2: - // "23 Jun" - $txt = strftime('%d %b',$datestamp); - break; - case DAYSTYLE_SHORTDATE3: - // "Mon 23" - $txt = strftime('%a %d',$datestamp); - break; - case DAYSTYLE_SHORTDATE4: - // "23" - $txt = strftime('%d',$datestamp); - break; - case DAYSTYLE_CUSTOM: - // Custom format - $txt = strftime($this->day->iLabelFormStr,$datestamp); - break; - case DAYSTYLE_ONELETTER: - default: - // "M" - $txt = strftime('%A',$datestamp); - $txt = strtoupper($txt[0]); - break; - } - - if( $day==0 ) - $img->SetColor($this->day->iSundayTextColor); - else - $img->SetColor($this->day->iTextColor); - $img->StrokeText(round($x+$daywidth/2+1), - round($yb-$this->day->iTitleVertMargin),$txt); - $img->SetColor($this->day->grid->iColor); - $img->SetLineWeight($this->day->grid->iWeight); - $img->Line($x,$yt,$x,$yb); - $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); - $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); - //$datestamp += SECPERDAY; - - } - $img->SetColor($this->day->iFrameColor); - $img->SetLineWeight($this->day->iFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - return $yb - $img->top_margin; - } - return $aYCoord; - } - - // Stroke week header and grid - function StrokeWeeks($aYCoord,$getHeight=false) { - if( $this->week->iShowLabels ) { - $img=$this->iImg; - $yt=$aYCoord+$img->top_margin; - $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); - $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; - - if( $getHeight ) { - return $yb - $img->top_margin; - } - - $xt=$img->left_margin+$this->iLabelWidth; - $weekwidth=$this->GetDayWidth()*7; - $wdays=$this->iDateLocale->GetDayAbb(); - $xb=$img->width-$img->right_margin+1; - $week = $this->iStartDate; - $weeknbr=$this->GetWeekNbr($week); - $img->SetColor($this->week->iBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - $img->SetColor($this->week->grid->iColor); - $x = $xt; - if( $this->week->iStyle==WEEKSTYLE_WNBR ) { - $img->SetTextAlign("center"); - $txtOffset = $weekwidth/2+1; - } - elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || - $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || - $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || - $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { - $img->SetTextAlign("left"); - $txtOffset = 3; - } - else { - JpGraphError::RaiseL(6021); - //("Unknown formatting style for week."); - } - - for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { - $img->PushColor($this->week->iTextColor); - - if( $this->week->iStyle==WEEKSTYLE_WNBR ) - $txt = sprintf($this->week->iLabelFormStr,$weeknbr); - elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || - $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) - $txt = date("j/n",$week); - elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || - $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { - $monthnbr = date("n",$week)-1; - $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); - $txt = Date("j",$week)." ".$shortmonth; - } - - if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || - $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { - $w = sprintf($this->week->iLabelFormStr,$weeknbr); - $txt .= ' '.$w; - } - - $img->StrokeText(round($x+$txtOffset), - round($yb-$this->week->iTitleVertMargin),$txt); - - $week = strtotime('+7 day',$week); - $weeknbr = $this->GetWeekNbr($week); - $img->PopColor(); - $img->SetLineWeight($this->week->grid->iWeight); - $img->Line($x,$yt,$x,$yb); - $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); - } - $img->SetColor($this->week->iFrameColor); - $img->SetLineWeight($this->week->iFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - return $yb-$img->top_margin; - } - return $aYCoord; - } - - // Format the mont scale header string - function GetMonthLabel($aMonthNbr,$year) { - $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); - $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); - switch($this->month->iStyle) { - case MONTHSTYLE_SHORTNAME: - $m=$sn; - break; - case MONTHSTYLE_LONGNAME: - $m=$ln; - break; - case MONTHSTYLE_SHORTNAMEYEAR2: - $m=$sn." '".substr("".$year,2); - break; - case MONTHSTYLE_SHORTNAMEYEAR4: - $m=$sn." ".$year; - break; - case MONTHSTYLE_LONGNAMEYEAR2: - $m=$ln." '".substr("".$year,2); - break; - case MONTHSTYLE_LONGNAMEYEAR4: - $m=$ln." ".$year; - break; - case MONTHSTYLE_FIRSTLETTER: - $m=$sn[0]; - break; - } - return $m; - } - - // Stroke month scale and gridlines - function StrokeMonths($aYCoord,$getHeight=false) { - if( $this->month->iShowLabels ) { - $img=$this->iImg; - $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); - $yt=$aYCoord+$img->top_margin; - $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; - if( $getHeight ) { - return $yb - $img->top_margin; - } - $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; - $xt=$img->left_margin+$this->iLabelWidth; - $xb=$img->width-$img->right_margin+1; - - $img->SetColor($this->month->iBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - - $img->SetLineWeight($this->month->grid->iWeight); - $img->SetColor($this->month->iTextColor); - $year = 0+strftime("%Y",$this->iStartDate); - $img->SetTextAlign("center"); - if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) - && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) { - $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1); - } - else { - $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); - } - // Is it enough space to stroke the first month? - $monthName = $this->GetMonthLabel($monthnbr,$year); - if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { - $img->SetColor($this->month->iTextColor); - $img->StrokeText(round($xt+$monthwidth/2+1), - round($yb-$this->month->iTitleVertMargin), - $monthName); - } - $x = $xt + $monthwidth; - while( $x < $xb ) { - $img->SetColor($this->month->grid->iColor); - $img->Line($x,$yt,$x,$yb); - $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); - $monthnbr++; - if( $monthnbr==12 ) { - $monthnbr=0; - $year++; - } - $monthName = $this->GetMonthLabel($monthnbr,$year); - $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); - if( $x + $monthwidth < $xb ) - $w = $monthwidth; - else - $w = $xb-$x; - if( $w >= 1.2*$img->GetTextWidth($monthName) ) { - $img->SetColor($this->month->iTextColor); - $img->StrokeText(round($x+$w/2+1), - round($yb-$this->month->iTitleVertMargin),$monthName); - } - $x += $monthwidth; - } - $img->SetColor($this->month->iFrameColor); - $img->SetLineWeight($this->month->iFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - return $yb-$img->top_margin; - } - return $aYCoord; - } - - // Stroke year scale and gridlines - function StrokeYears($aYCoord,$getHeight=false) { - if( $this->year->iShowLabels ) { - $img=$this->iImg; - $yt=$aYCoord+$img->top_margin; - $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); - $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; - - if( $getHeight ) { - return $yb - $img->top_margin; - } - - $xb=$img->width-$img->right_margin+1; - $xt=$img->left_margin+$this->iLabelWidth; - $year = $this->GetYear($this->iStartDate); - $img->SetColor($this->year->iBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - $img->SetLineWeight($this->year->grid->iWeight); - $img->SetTextAlign("center"); - if( $year == $this->GetYear($this->iEndDate) ) - $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); - else - $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); - - // The space for a year must be at least 20% bigger than the actual text - // so we allow 10% margin on each side - if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { - $img->SetColor($this->year->iTextColor); - $img->StrokeText(round($xt+$yearwidth/2+1), - round($yb-$this->year->iTitleVertMargin), - $year); - } - $x = $xt + $yearwidth; - while( $x < $xb ) { - $img->SetColor($this->year->grid->iColor); - $img->Line($x,$yt,$x,$yb); - $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); - $year += 1; - $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); - if( $x + $yearwidth < $xb ) - $w = $yearwidth; - else - $w = $xb-$x; - if( $w >= 1.2*$img->GetTextWidth("".$year) ) { - $img->SetColor($this->year->iTextColor); - $img->StrokeText(round($x+$w/2+1), - round($yb-$this->year->iTitleVertMargin), - $year); - } - $x += $yearwidth; - } - $img->SetColor($this->year->iFrameColor); - $img->SetLineWeight($this->year->iFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - return $yb-$img->top_margin; - } - return $aYCoord; - } - - // Stroke table title (upper left corner) - function StrokeTableHeaders($aYBottom) { - $img=$this->iImg; - $xt=$img->left_margin; - $yt=$img->top_margin; - $xb=$xt+$this->iLabelWidth; - $yb=$aYBottom+$img->top_margin; - - if( $this->tableTitle->iShow ) { - $img->SetColor($this->iTableHeaderBackgroundColor); - $img->FilledRectangle($xt,$yt,$xb,$yb); - $this->tableTitle->Align("center","top"); - $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2); - $img->SetColor($this->iTableHeaderFrameColor); - $img->SetLineWeight($this->iTableHeaderFrameWeight); - $img->Rectangle($xt,$yt,$xb,$yb); - } - - $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow); - - - // Draw the horizontal dividing line - $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); - - // Draw the vertical dividing line - // We do the width "manually" since we want the line only to grow - // to the left - $fancy = $this->divider->iStyle == 'fancy' ; - if( $fancy ) { - $this->divider->iStyle = 'solid'; - } - - $tmp = $this->divider->iWeight; - $this->divider->iWeight=1; - $y = $img->height-$img->bottom_margin; - for($i=0; $i < $tmp; ++$i ) { - $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y); - } - - // Should we draw "fancy" divider - if( $fancy ) { - $img->SetLineWeight(1); - $img->SetColor($this->iTableHeaderFrameColor); - $img->Line($xb,$yt,$xb,$y); - $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y); - $img->SetColor('white'); - $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y); - } - } - - // Main entry point to stroke scale - function Stroke() { - if( !$this->IsRangeSet() ) { - JpGraphError::RaiseL(6022); - //("Gantt scale has not been specified."); - } - $img=$this->iImg; - - // If minutes are displayed then hour interval must be 1 - if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) { - JpGraphError::RaiseL(6023); - //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).'); - } - - // Stroke all headers. As argument we supply the offset from the - // top which depends on any previous headers - - // First find out the height of each header - $offy=$this->StrokeYears(0,true); - $offm=$this->StrokeMonths($offy,true); - $offw=$this->StrokeWeeks($offm,true); - $offd=$this->StrokeDays($offw,true); - $offh=$this->StrokeHours($offd,true); - $offmin=$this->StrokeMinutes($offh,true); - - - // ... then we can stroke them in the "backwards order to ensure that - // the larger scale gridlines is stroked over the smaller scale gridline - $this->StrokeMinutes($offh); - $this->StrokeHours($offd); - $this->StrokeDays($offw); - $this->StrokeWeeks($offm); - $this->StrokeMonths($offy); - $this->StrokeYears(0); - - // Now when we now the oaverall size of the scale headers - // we can stroke the overall table headers - $this->StrokeTableHeaders($offmin); - - // Now we can calculate the correct scaling factor for each vertical position - $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; - - $this->iVertHeaderSize = $offmin; - if( $this->iVertSpacing == -1 ) - $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; - } -} - - -//=================================================== -// CLASS GanttConstraint -// Just a structure to store all the values for a constraint -//=================================================== -class GanttConstraint { - public $iConstrainRow; - public $iConstrainType; - public $iConstrainColor; - public $iConstrainArrowSize; - public $iConstrainArrowType; - - //--------------- - // CONSTRUCTOR - function __construct($aRow,$aType,$aColor,$aArrowSize,$aArrowType){ - $this->iConstrainType = $aType; - $this->iConstrainRow = $aRow; - $this->iConstrainColor=$aColor; - $this->iConstrainArrowSize=$aArrowSize; - $this->iConstrainArrowType=$aArrowType; - } -} - - -//=================================================== -// CLASS GanttPlotObject -// The common signature for a Gantt object -//=================================================== -class GanttPlotObject { - public $title,$caption; - public $csimarea='',$csimtarget='',$csimwintarget='',$csimalt=''; - public $constraints = array(); - public $iCaptionMargin=5; - public $iConstrainPos=array(); - protected $iStart=""; // Start date - public $iVPos=0; // Vertical position - protected $iLabelLeftMargin=2; // Title margin - - function __construct() { - $this->title = new TextProperty(); - $this->title->Align('left','center'); - $this->caption = new TextProperty(); - } - - function GetCSIMArea() { - return $this->csimarea; - } - - function SetCSIMTarget($aTarget,$aAlt='',$aWinTarget='') { - if( !is_string($aTarget) ) { - $tv = substr(var_export($aTarget,true),0,40); - JpGraphError::RaiseL(6024,$tv); - //('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv"); - } - if( !is_string($aAlt) ) { - $tv = substr(var_export($aAlt,true),0,40); - JpGraphError::RaiseL(6025,$tv); - //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); - } - - $this->csimtarget=$aTarget; - $this->csimwintarget=$aWinTarget; - $this->csimalt=$aAlt; - } - - function SetCSIMAlt($aAlt) { - if( !is_string($aAlt) ) { - $tv = substr(var_export($aAlt,true),0,40); - JpGraphError::RaiseL(6025,$tv); - //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); - } - $this->csimalt=$aAlt; - } - - function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) { - $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType); - } - - function SetConstrainPos($xt,$yt,$xb,$yb) { - $this->iConstrainPos = array($xt,$yt,$xb,$yb); - } - - function GetMinDate() { - return $this->iStart; - } - - function GetMaxDate() { - return $this->iStart; - } - - function SetCaptionMargin($aMarg) { - $this->iCaptionMargin=$aMarg; - } - - function GetAbsHeight($aImg) { - return 0; - } - - function GetLineNbr() { - return $this->iVPos; - } - - function SetLabelLeftMargin($aOff) { - $this->iLabelLeftMargin=$aOff; - } - - function StrokeActInfo($aImg,$aScale,$aYPos) { - $cols=array(); - $aScale->actinfo->GetColStart($aImg,$cols,true); - $this->title->Stroke($aImg,$cols,$aYPos); - } -} - -//=================================================== -// CLASS Progress -// Holds parameters for the progress indicator -// displyed within a bar -//=================================================== -class Progress { - public $iProgress=-1; - public $iPattern=GANTT_SOLID; - public $iColor="black", $iFillColor='black'; - public $iDensity=98, $iHeight=0.65; - - function Set($aProg) { - if( $aProg < 0.0 || $aProg > 1.0 ) { - JpGraphError::RaiseL(6027); - //("Progress value must in range [0, 1]"); - } - $this->iProgress = $aProg; - } - - function SetPattern($aPattern,$aColor="blue",$aDensity=98) { - $this->iPattern = $aPattern; - $this->iColor = $aColor; - $this->iDensity = $aDensity; - } - - function SetFillColor($aColor) { - $this->iFillColor = $aColor; - } - - function SetHeight($aHeight) { - $this->iHeight = $aHeight; - } -} - -define('GANTT_HGRID1',0); -define('GANTT_HGRID2',1); - -//=================================================== -// CLASS HorizontalGridLine -// Responsible for drawinf horizontal gridlines and filled alternatibg rows -//=================================================== -class HorizontalGridLine { - private $iGraph=NULL; - private $iRowColor1 = '', $iRowColor2 = ''; - private $iShow=false; - private $line=null; - private $iStart=0; // 0=from left margin, 1=just along header - - function __construct() { - $this->line = new LineProperty(); - $this->line->SetColor('gray@0.4'); - $this->line->SetStyle('dashed'); - } - - function Show($aShow=true) { - $this->iShow = $aShow; - } - - function SetRowFillColor($aColor1,$aColor2='') { - $this->iRowColor1 = $aColor1; - $this->iRowColor2 = $aColor2; - } - - function SetStart($aStart) { - $this->iStart = $aStart; - } - - function Stroke($aImg,$aScale) { - - if( ! $this->iShow ) return; - - // Get horizontal width of line - /* - $limst = $aScale->iStartDate; - $limen = $aScale->iEndDate; - $xt = round($aScale->TranslateDate($aScale->iStartDate)); - $xb = round($aScale->TranslateDate($limen)); - */ - - if( $this->iStart === 0 ) { - $xt = $aImg->left_margin-1; - } - else { - $xt = round($aScale->TranslateDate($aScale->iStartDate))+1; - } - - $xb = $aImg->width-$aImg->right_margin; - - $yt = round($aScale->TranslateVertPos(0)); - $yb = round($aScale->TranslateVertPos(1)); - $height = $yb - $yt; - - // Loop around for all lines in the chart - for($i=0; $i < $aScale->iVertLines; ++$i ) { - $yb = $yt - $height; - $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); - if( $this->iRowColor1 !== '' ) { - if( $i % 2 == 0 ) { - $aImg->PushColor($this->iRowColor1); - $aImg->FilledRectangle($xt,$yt,$xb,$yb); - $aImg->PopColor(); - } - elseif( $this->iRowColor2 !== '' ) { - $aImg->PushColor($this->iRowColor2); - $aImg->FilledRectangle($xt,$yt,$xb,$yb); - $aImg->PopColor(); - } - } - $yt = round($aScale->TranslateVertPos($i+1)); - } - $yb = $yt - $height; - $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); - } -} - - -//=================================================== -// CLASS GanttBar -// Responsible for formatting individual gantt bars -//=================================================== -class GanttBar extends GanttPlotObject { - public $progress; - public $leftMark,$rightMark; - private $iEnd; - private $iHeightFactor=0.5; - private $iFillColor="white",$iFrameColor="black"; - private $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; - private $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; - private $iBreakStyle=false, $iBreakLineStyle='dotted',$iBreakLineWeight=1; - //--------------- - // CONSTRUCTOR - function __construct($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { - parent::__construct(); - $this->iStart = $aStart; - // Is the end date given as a date or as number of days added to start date? - if( is_string($aEnd) ) { - // If end date has been specified without a time we will asssume - // end date is at the end of that date - if( strpos($aEnd,':') === false ) { - $this->iEnd = strtotime($aEnd)+SECPERDAY-1; - } - else { - $this->iEnd = $aEnd; - } - } - elseif(is_int($aEnd) || is_float($aEnd) ) { - $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); - } - $this->iVPos = $aPos; - $this->iHeightFactor = $aHeightFactor; - $this->title->Set($aLabel); - $this->caption = new TextProperty($aCaption); - $this->caption->Align("left","center"); - $this->leftMark =new PlotMark(); - $this->leftMark->Hide(); - $this->rightMark=new PlotMark(); - $this->rightMark->Hide(); - $this->progress = new Progress(); - } - - //--------------- - // PUBLIC METHODS - function SetShadow($aShadow=true,$aColor="gray") { - $this->iShadow=$aShadow; - $this->iShadowColor=$aColor; - } - - function SetBreakStyle($aFlg=true,$aLineStyle='dotted',$aLineWeight=1) { - $this->iBreakStyle = $aFlg; - $this->iBreakLineStyle = $aLineStyle; - $this->iBreakLineWeight = $aLineWeight; - } - - function GetMaxDate() { - return $this->iEnd; - } - - function SetHeight($aHeight) { - $this->iHeightFactor = $aHeight; - } - - function SetColor($aColor) { - $this->iFrameColor = $aColor; - } - - function SetFillColor($aColor) { - $this->iFillColor = $aColor; - } - - function GetAbsHeight($aImg) { - if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { - $m=-1; - if( is_int($this->iHeightFactor) ) - $m = $this->iHeightFactor; - if( $this->leftMark->show ) - $m = max($m,$this->leftMark->width*2); - if( $this->rightMark->show ) - $m = max($m,$this->rightMark->width*2); - return $m; - } - else - return -1; - } - - function SetPattern($aPattern,$aColor="blue",$aDensity=95) { - $this->iPattern = $aPattern; - $this->iPatternColor = $aColor; - $this->iPatternDensity = $aDensity; - } - - function Stroke($aImg,$aScale) { - $factory = new RectPatternFactory(); - $prect = $factory->Create($this->iPattern,$this->iPatternColor); - $prect->SetDensity($this->iPatternDensity); - - // If height factor is specified as a float between 0,1 then we take it as meaning - // percetage of the scale width between horizontal line. - // If it is an integer > 1 we take it to mean the absolute height in pixels - if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) - $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; - elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 ) - $vs = $this->iHeightFactor; - else { - JpGraphError::RaiseL(6028,$this->iHeightFactor); - // ("Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); - } - - // Clip date to min max dates to show - $st = $aScale->NormalizeDate($this->iStart); - $en = $aScale->NormalizeDate($this->iEnd); - - $limst = max($st,$aScale->iStartDate); - $limen = min($en,$aScale->iEndDate); - - $xt = round($aScale->TranslateDate($limst)); - $xb = round($aScale->TranslateDate($limen)); - $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2)); - $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2)); - $middle = round($yt+($yb-$yt)/2); - $this->StrokeActInfo($aImg,$aScale,$middle); - - // CSIM for title - if( ! empty($this->title->csimtarget) ) { - $colwidth = $this->title->GetColWidth($aImg); - $colstarts=array(); - $aScale->actinfo->GetColStart($aImg,$colstarts,true); - $n = min(count($colwidth),count($this->title->csimtarget)); - for( $i=0; $i < $n; ++$i ) { - $title_xt = $colstarts[$i]; - $title_xb = $title_xt + $colwidth[$i]; - $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; - - if( ! empty($this->title->csimtarget[$i]) ) { - $this->csimarea .= "title->csimtarget[$i]."\""; - - if( ! empty($this->title->csimwintarget[$i]) ) { - $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\" "; - } - - if( ! empty($this->title->csimalt[$i]) ) { - $tmp = $this->title->csimalt[$i]; - $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimarea .= " />\n"; - } - } - } - - // Check if the bar is totally outside the current scale range - if( $en < $aScale->iStartDate || $st > $aScale->iEndDate ) - return; - - - // Remember the positions for the bar - $this->SetConstrainPos($xt,$yt,$xb,$yb); - - - - $prect->ShowFrame(false); - $prect->SetBackground($this->iFillColor); - if( $this->iBreakStyle ) { - $aImg->SetColor($this->iFrameColor); - $olds = $aImg->SetLineStyle($this->iBreakLineStyle); - $oldw = $aImg->SetLineWeight($this->iBreakLineWeight); - $aImg->StyleLine($xt,$yt,$xb,$yt); - $aImg->StyleLine($xt,$yb,$xb,$yb); - $aImg->SetLineStyle($olds); - $aImg->SetLineWeight($oldw); - } - else { - if( $this->iShadow ) { - $aImg->SetColor($this->iFrameColor); - $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); - $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); - $prect->Stroke($aImg); - } - else { - $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); - $prect->Stroke($aImg); - $aImg->SetColor($this->iFrameColor); - $aImg->Rectangle($xt,$yt,$xb,$yb); - } - } - // CSIM for bar - if( ! empty($this->csimtarget) ) { - - $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb"; - $this->csimarea .= "csimtarget."\""; - - if( !empty($this->csimwintarget) ) { - $this->csimarea .= " target=\"".$this->csimwintarget."\" "; - } - - if( $this->csimalt != '' ) { - $tmp = $this->csimalt; - $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimarea .= " />\n"; - } - - // Draw progress bar inside activity bar - if( $this->progress->iProgress > 0 ) { - - $xtp = $aScale->TranslateDate($st); - $xbp = $aScale->TranslateDate($en); - $len = ($xbp-$xtp)*$this->progress->iProgress; - - $endpos = $xtp+$len; - if( $endpos > $xt ) { - - // Take away the length of the progress that is not visible (before the start date) - $len -= ($xt-$xtp); - - // Is the the progress bar visible after the start date? - if( $xtp < $xt ) - $xtp = $xt; - - // Make sure that the progess bar doesn't extend over the end date - if( $xtp+$len-1 > $xb ) - $len = $xb - $xtp ; - - $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); - $prog->SetDensity($this->progress->iDensity); - $prog->SetBackground($this->progress->iFillColor); - $barheight = ($yb-$yt+1); - if( $this->iShadow ) - $barheight -= $this->iShadowWidth; - $progressheight = floor($barheight*$this->progress->iHeight); - $marg = ceil(($barheight-$progressheight)/2); - $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg); - $prog->SetPos($pos); - $prog->Stroke($aImg); - } - } - - // We don't plot the end mark if the bar has been capped - if( $limst == $st ) { - $y = $middle; - // We treat the RIGHT and LEFT triangle mark a little bi - // special so that these marks are placed right under the - // bar. - if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) { - $y = $yb ; - } - $this->leftMark->Stroke($aImg,$xt,$y); - } - if( $limen == $en ) { - $y = $middle; - // We treat the RIGHT and LEFT triangle mark a little bi - // special so that these marks are placed right under the - // bar. - if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) { - $y = $yb ; - } - $this->rightMark->Stroke($aImg,$xb,$y); - - $margin = $this->iCaptionMargin; - if( $this->rightMark->show ) - $margin += $this->rightMark->GetWidth(); - $this->caption->Stroke($aImg,$xb+$margin,$middle); - } - } -} - -//=================================================== -// CLASS MileStone -// Responsible for formatting individual milestones -//=================================================== -class MileStone extends GanttPlotObject { - public $mark; - - //--------------- - // CONSTRUCTOR - function __construct($aVPos,$aLabel,$aDate,$aCaption="") { - GanttPlotObject::__construct(); - $this->caption->Set($aCaption); - $this->caption->Align("left","center"); - $this->caption->SetFont(FF_FONT1,FS_BOLD); - $this->title->Set($aLabel); - $this->title->SetColor("darkred"); - $this->mark = new PlotMark(); - $this->mark->SetWidth(10); - $this->mark->SetType(MARK_DIAMOND); - $this->mark->SetColor("darkred"); - $this->mark->SetFillColor("darkred"); - $this->iVPos = $aVPos; - $this->iStart = $aDate; - } - - //--------------- - // PUBLIC METHODS - - function GetAbsHeight($aImg) { - return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); - } - - function Stroke($aImg,$aScale) { - // Put the mark in the middle at the middle of the day - $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2; - $x = $aScale->TranslateDate($d); - $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); - - $this->StrokeActInfo($aImg,$aScale,$y); - - // CSIM for title - if( ! empty($this->title->csimtarget) ) { - - $yt = round($y - $this->title->GetHeight($aImg)/2); - $yb = round($y + $this->title->GetHeight($aImg)/2); - - $colwidth = $this->title->GetColWidth($aImg); - $colstarts=array(); - $aScale->actinfo->GetColStart($aImg,$colstarts,true); - $n = min(count($colwidth),count($this->title->csimtarget)); - for( $i=0; $i < $n; ++$i ) { - $title_xt = $colstarts[$i]; - $title_xb = $title_xt + $colwidth[$i]; - $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; - - if( !empty($this->title->csimtarget[$i]) ) { - - $this->csimarea .= "title->csimtarget[$i]."\""; - - if( !empty($this->title->csimwintarget[$i]) ) { - $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\""; - } - - if( ! empty($this->title->csimalt[$i]) ) { - $tmp = $this->title->csimalt[$i]; - $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimarea .= " />\n"; - } - } - } - - if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) - return; - - // Remember the coordinates for any constrains linking to - // this milestone - $w = $this->mark->GetWidth()/2; - $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w)); - - // Setup CSIM - if( $this->csimtarget != '' ) { - $this->mark->SetCSIMTarget( $this->csimtarget ); - $this->mark->SetCSIMAlt( $this->csimalt ); - } - - $this->mark->Stroke($aImg,$x,$y); - $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); - - $this->csimarea .= $this->mark->GetCSIMAreas(); - } -} - - -//=================================================== -// CLASS GanttVLine -// Responsible for formatting individual milestones -//=================================================== - -class TextPropertyBelow extends TextProperty { - function __construct($aTxt='') { - parent::__construct($aTxt); - } - - function GetColWidth($aImg,$aMargin=0) { - // Since we are not stroking the title in the columns - // but rather under the graph we want this to return 0. - return array(0); - } -} - -class GanttVLine extends GanttPlotObject { - - private $iLine,$title_margin=3, $iDayOffset=0.5; - private $iStartRow = -1, $iEndRow = -1; - - //--------------- - // CONSTRUCTOR - function __construct($aDate,$aTitle="",$aColor="darkred",$aWeight=2,$aStyle="solid") { - GanttPlotObject::__construct(); - $this->iLine = new LineProperty(); - $this->iLine->SetColor($aColor); - $this->iLine->SetWeight($aWeight); - $this->iLine->SetStyle($aStyle); - $this->iStart = $aDate; - $this->title = new TextPropertyBelow(); - $this->title->Set($aTitle); - } - - //--------------- - // PUBLIC METHODS - - // Set start and end rows for the VLine. By default the entire heigh of the - // Gantt chart is used - function SetRowSpan($aStart, $aEnd=-1) { - $this->iStartRow = $aStart; - $this->iEndRow = $aEnd; - } - - function SetDayOffset($aOff=0.5) { - if( $aOff < 0.0 || $aOff > 1.0 ) { - JpGraphError::RaiseL(6029); - //("Offset for vertical line must be in range [0,1]"); - } - $this->iDayOffset = $aOff; - } - - function SetTitleMargin($aMarg) { - $this->title_margin = $aMarg; - } - - function SetWeight($aWeight) { - $this->iLine->SetWeight($aWeight); - } - - function Stroke($aImg,$aScale) { - $d = $aScale->NormalizeDate($this->iStart); - if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) - return; - if($this->iDayOffset != 0.0) - $d += 24*60*60*$this->iDayOffset; - $x = $aScale->TranslateDate($d);//d=1006858800, - - if( $this->iStartRow > -1 ) { - $y1 = $aScale->TranslateVertPos($this->iStartRow,true) ; - } - else { - $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; - } - - if( $this->iEndRow > -1 ) { - $y2 = $aScale->TranslateVertPos($this->iEndRow); - } - else { - $y2 = $aImg->height - $aImg->bottom_margin; - } - - $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); - $this->title->Align("center","top"); - $this->title->Stroke($aImg,$x,$y2+$this->title_margin); - } -} - -//=================================================== -// CLASS LinkArrow -// Handles the drawing of a an arrow -//=================================================== -class LinkArrow { - private $ix,$iy; - private $isizespec = array( - array(2,3),array(3,5),array(3,8),array(6,15),array(8,22)); - private $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2; - private $iColor='black'; - - function __construct($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) { - $this->iDirection = $aDirection; - $this->iType = $aType; - $this->iSize = $aSize; - $this->ix = $x; - $this->iy = $y; - } - - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function SetSize($aSize) { - $this->iSize = $aSize; - } - - function SetType($aType) { - $this->iType = $aType; - } - - function Stroke($aImg) { - list($dx,$dy) = $this->isizespec[$this->iSize]; - $x = $this->ix; - $y = $this->iy; - switch ( $this->iDirection ) { - case ARROW_DOWN: - $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y); - break; - case ARROW_UP: - $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y); - break; - case ARROW_LEFT: - $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y); - break; - case ARROW_RIGHT: - $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y); - break; - default: - JpGraphError::RaiseL(6030); - //('Unknown arrow direction for link.'); - die(); - break; - } - $aImg->SetColor($this->iColor); - switch( $this->iType ) { - case ARROWT_SOLID: - $aImg->FilledPolygon($c); - break; - case ARROWT_OPEN: - $aImg->Polygon($c); - break; - default: - JpGraphError::RaiseL(6031); - //('Unknown arrow type for link.'); - die(); - break; - } - } -} - -//=================================================== -// CLASS GanttLink -// Handles the drawing of a link line between 2 points -//=================================================== - -class GanttLink { - private $ix1,$ix2,$iy1,$iy2; - private $iPathType=2,$iPathExtend=15; - private $iColor='black',$iWeight=1; - private $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID; - - function __construct($x1=0,$y1=0,$x2=0,$y2=0) { - $this->ix1 = $x1; - $this->ix2 = $x2; - $this->iy1 = $y1; - $this->iy2 = $y2; - } - - function SetPos($x1,$y1,$x2,$y2) { - $this->ix1 = $x1; - $this->ix2 = $x2; - $this->iy1 = $y1; - $this->iy2 = $y2; - } - - function SetPath($aPath) { - $this->iPathType = $aPath; - } - - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function SetArrow($aSize,$aType=ARROWT_SOLID) { - $this->iArrowSize = $aSize; - $this->iArrowType = $aType; - } - - function SetWeight($aWeight) { - $this->iWeight = $aWeight; - } - - function Stroke($aImg) { - // The way the path for the arrow is constructed is partly based - // on some heuristics. This is not an exact science but draws the - // path in a way that, for me, makes esthetic sence. For example - // if the start and end activities are very close we make a small - // detour to endter the target horixontally. If there are more - // space between axctivities then no suh detour is made and the - // target is "hit" directly vertical. I have tried to keep this - // simple. no doubt this could become almost infinitive complex - // and have some real AI. Feel free to modify this. - // This will no-doubt be tweaked as times go by. One design aim - // is to avoid having the user choose what types of arrow - // he wants. - - // The arrow is drawn between (x1,y1) to (x2,y2) - $x1 = $this->ix1 ; - $x2 = $this->ix2 ; - $y1 = $this->iy1 ; - $y2 = $this->iy2 ; - - // Depending on if the target is below or above we have to - // handle thi different. - if( $y2 > $y1 ) { - $arrowtype = ARROW_DOWN; - $midy = round(($y2-$y1)/2+$y1); - if( $x2 > $x1 ) { - switch ( $this->iPathType ) { - case 0: - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - break; - case 1: - case 2: - case 3: - $c = array($x1,$y1,$x2,$y1,$x2,$y2); - break; - default: - JpGraphError::RaiseL(6032,$this->iPathType); - //('Internal error: Unknown path type (='.$this->iPathType .') specified for link.'); - exit(1); - break; - } - } - else { - switch ( $this->iPathType ) { - case 0: - case 1: - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - break; - case 2: - // Always extend out horizontally a bit from the first point - // If we draw a link back in time (end to start) and the bars - // are very close we also change the path so it comes in from - // the left on the activity - $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, - $x1+$this->iPathExtend,$midy, - $x2,$midy,$x2,$y2); - break; - case 3: - if( $y2-$midy < 6 ) { - $c = array($x1,$y1,$x1,$midy, - $x2-$this->iPathExtend,$midy, - $x2-$this->iPathExtend,$y2, - $x2,$y2); - $arrowtype = ARROW_RIGHT; - } - else { - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - } - break; - default: - JpGraphError::RaiseL(6032,$this->iPathType); - //('Internal error: Unknown path type specified for link.'); - exit(1); - break; - } - } - $arrow = new LinkArrow($x2,$y2,$arrowtype); - } - else { - // Y2 < Y1 - $arrowtype = ARROW_UP; - $midy = round(($y1-$y2)/2+$y2); - if( $x2 > $x1 ) { - switch ( $this->iPathType ) { - case 0: - case 1: - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - break; - case 3: - if( $midy-$y2 < 8 ) { - $arrowtype = ARROW_RIGHT; - $c = array($x1,$y1,$x1,$y2,$x2,$y2); - } - else { - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - } - break; - default: - JpGraphError::RaiseL(6032,$this->iPathType); - //('Internal error: Unknown path type specified for link.'); - break; - } - } - else { - switch ( $this->iPathType ) { - case 0: - case 1: - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - break; - case 2: - // Always extend out horizontally a bit from the first point - $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, - $x1+$this->iPathExtend,$midy, - $x2,$midy,$x2,$y2); - break; - case 3: - if( $midy-$y2 < 16 ) { - $arrowtype = ARROW_RIGHT; - $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy, - $x2-$this->iPathExtend,$y2, - $x2,$y2); - } - else { - $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); - } - break; - default: - JpGraphError::RaiseL(6032,$this->iPathType); - //('Internal error: Unknown path type specified for link.'); - break; - } - } - $arrow = new LinkArrow($x2,$y2,$arrowtype); - } - $aImg->SetColor($this->iColor); - $aImg->SetLineWeight($this->iWeight); - $aImg->Polygon($c); - $aImg->SetLineWeight(1); - $arrow->SetColor($this->iColor); - $arrow->SetSize($this->iArrowSize); - $arrow->SetType($this->iArrowType); - $arrow->Stroke($aImg); - } -} - -// -?> +vgrid = new LineProperty(); + } + + function Hide($aF=true) { + $this->iShow=!$aF; + } + + function Show($aF=true) { + $this->iShow=$aF; + } + + // Specify font + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function SetColumnMargin($aLeft,$aRight) { + $this->iLeftColMargin = $aLeft; + $this->iRightColMargin = $aRight; + } + + function SetFontColor($aFontColor) { + $this->iFontColor = $aFontColor; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetBackgroundColor($aColor) { + $this->iBackgroundColor = $aColor; + } + + function SetColTitles($aTitles,$aWidth=null) { + $this->iTitles = $aTitles; + $this->iWidth = $aWidth; + } + + function SetMinColWidth($aWidths) { + $n = min(count($this->iTitles),count($aWidths)); + for($i=0; $i < $n; ++$i ) { + if( !empty($aWidths[$i]) ) { + if( empty($this->iWidth[$i]) ) { + $this->iWidth[$i] = $aWidths[$i]; + } + else { + $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]); + } + } + } + } + + function GetWidth($aImg) { + $txt = new TextProperty(); + $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $n = count($this->iTitles) ; + $rm=$this->iRightColMargin; + $w = 0; + for($h=0, $i=0; $i < $n; ++$i ) { + $w += $this->iLeftColMargin; + $txt->Set($this->iTitles[$i]); + if( !empty($this->iWidth[$i]) ) { + $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]); + } + else { + $w1 = $txt->GetWidth($aImg)+$rm; + } + $this->iWidth[$i] = $w1; + $w += $w1; + $h = max($h,$txt->GetHeight($aImg)); + } + $this->iHeight = $h+$this->iTopHeaderMargin; + $txt=''; + return $w; + } + + function GetColStart($aImg,&$aStart,$aAddLeftMargin=false) { + $n = count($this->iTitles) ; + $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0; + $aStart=array($aImg->left_margin+$adj); + for( $i=1; $i < $n; ++$i ) { + $aStart[$i] = $aStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1]; + } + } + + // Adjust headers left, right or centered + function SetHeaderAlign($aAlign) { + $this->iHeaderAlign=$aAlign; + } + + function Stroke($aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) { + + if( !$this->iShow ) return; + + $txt = new TextProperty(); + $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $txt->SetColor($this->iFontColor); + $txt->SetAlign($this->iHeaderAlign,'top'); + $n=count($this->iTitles); + + if( $n == 0 ) + return; + + $x = $aXLeft; + $h = $this->iHeight; + $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ; + + if( $h < 0 ) { + JpGraphError::RaiseL(6001); + //('Internal error. Height for ActivityTitles is < 0'); + } + + $aImg->SetLineWeight(1); + // Set background color + $aImg->SetColor($this->iBackgroundColor); + $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1); + + if( $this->iStyle == 1 ) { + // Make a 3D effect + $aImg->SetColor('white'); + $aImg->Line($aXLeft,$yTop+1,$aXRight,$yTop+1); + } + + for($i=0; $i < $n; ++$i ) { + if( $this->iStyle == 1 ) { + // Make a 3D effect + $aImg->SetColor('white'); + $aImg->Line($x+1,$yTop,$x+1,$aYBottom); + } + $x += $this->iLeftColMargin; + $txt->Set($this->iTitles[$i]); + + // Adjust the text anchor position according to the choosen alignment + $xp = $x; + if( $this->iHeaderAlign == 'center' ) { + $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2; + } + elseif( $this->iHeaderAlign == 'right' ) { + $xp = $x +$this->iWidth[$i]-$this->iRightColMargin; + } + + $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin); + $x += $this->iWidth[$i]; + if( $i < $n-1 ) { + $aImg->SetColor($this->iColor); + $aImg->Line($x,$yTop,$x,$aYBottom); + } + } + + $aImg->SetColor($this->iColor); + $aImg->Line($aXLeft,$yTop, $aXRight,$yTop); + + // Stroke vertical column dividers + $cols=array(); + $this->GetColStart($aImg,$cols); + $n=count($cols); + for( $i=1; $i < $n; ++$i ) { + $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i], + $aImg->height - $aImg->bottom_margin); + } + } +} + + +//=================================================== +// CLASS GanttGraph +// Description: Main class to handle gantt graphs +//=================================================== +class GanttGraph extends Graph { + public $scale; // Public accessible + public $hgrid=null; + private $iObj=array(); // Gantt objects + private $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels + private $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label + private $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN + private $iSimpleFont = FF_FONT1,$iSimpleFontSize=11; + private $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red'; + private $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen'; + private $iSimpleProgressStyle=GANTT_SOLID; + private $iZoomFactor = 1.0; + //--------------- + // CONSTRUCTOR + // Create a new gantt graph + function __construct($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) { + + // Backward compatibility + if( $aWidth == -1 ) $aWidth=0; + if( $aHeight == -1 ) $aHeight=0; + + if( $aWidth< 0 || $aHeight < 0 ) { + JpgraphError::RaiseL(6002); + //("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension."); + } + parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); + $this->scale = new GanttScale($this->img); + + // Default margins + $this->img->SetMargin(15,17,25,15); + + $this->hgrid = new HorizontalGridLine(); + + $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); + $this->SetBox(); + } + + //--------------- + // PUBLIC METHODS + + // + + function SetSimpleFont($aFont,$aSize) { + $this->iSimpleFont = $aFont; + $this->iSimpleFontSize = $aSize; + } + + function SetSimpleStyle($aBand,$aColor,$aBkgColor) { + $this->iSimpleStyle = $aBand; + $this->iSimpleColor = $aColor; + $this->iSimpleBkgColor = $aBkgColor; + } + + // A utility function to help create basic Gantt charts + function CreateSimple($data,$constrains=array(),$progress=array()) { + $num = count($data); + for( $i=0; $i < $num; ++$i) { + switch( $data[$i][1] ) { + case ACTYPE_GROUP: + // Create a slightly smaller height bar since the + // "wings" at the end will make it look taller + $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8); + $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize); + $a->rightMark->Show(); + $a->rightMark->SetType(MARK_RIGHTTRIANGLE); + $a->rightMark->SetWidth(8); + $a->rightMark->SetColor('black'); + $a->rightMark->SetFillColor('black'); + + $a->leftMark->Show(); + $a->leftMark->SetType(MARK_LEFTTRIANGLE); + $a->leftMark->SetWidth(8); + $a->leftMark->SetColor('black'); + $a->leftMark->SetFillColor('black'); + + $a->SetPattern(BAND_SOLID,'black'); + $csimpos = 6; + break; + + case ACTYPE_NORMAL: + $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10); + $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor); + $a->SetFillColor($this->iSimpleBkgColor); + // Check if this activity should have a constrain line + $n = count($constrains); + for( $j=0; $j < $n; ++$j ) { + if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) { + JpGraphError::RaiseL(6003,$j); + //("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)"); + } + if( $constrains[$j][0]==$data[$i][0] ) { + $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID); + } + } + + // Check if this activity have a progress bar + $n = count($progress); + for( $j=0; $j < $n; ++$j ) { + + if( empty($progress[$j]) || (count($progress[$j]) != 2) ) { + JpGraphError::RaiseL(6004,$j); + //("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)"); + } + if( $progress[$j][0]==$data[$i][0] ) { + $a->progress->Set($progress[$j][1]); + $a->progress->SetPattern($this->iSimpleProgressStyle, + $this->iSimpleProgressColor); + $a->progress->SetFillColor($this->iSimpleProgressBkgColor); + //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]); + break; + } + } + $csimpos = 6; + break; + + case ACTYPE_MILESTONE: + $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]); + $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $csimpos = 5; + break; + default: + die('Unknown activity type'); + break; + } + + // Setup caption + $a->caption->Set($data[$i][$csimpos-1]); + + // Check if this activity should have a CSIM targetï¿œ? + if( !empty($data[$i][$csimpos]) ) { + $a->SetCSIMTarget($data[$i][$csimpos]); + $a->SetCSIMAlt($data[$i][$csimpos+1]); + } + if( !empty($data[$i][$csimpos+2]) ) { + $a->title->SetCSIMTarget($data[$i][$csimpos+2]); + $a->title->SetCSIMAlt($data[$i][$csimpos+3]); + } + + $this->Add($a); + } + } + + // Set user specified scale zoom factor when auto sizing is used + function SetZoomFactor($aZoom) { + $this->iZoomFactor = $aZoom; + } + + + // Set what headers should be shown + function ShowHeaders($aFlg) { + $this->scale->ShowHeaders($aFlg); + } + + // Specify the fraction of the font height that should be added + // as vertical margin + function SetLabelVMarginFactor($aVal) { + $this->iLabelVMarginFactor = $aVal; + } + + // Synonym to the method above + function SetVMarginFactor($aVal) { + $this->iLabelVMarginFactor = $aVal; + } + + + // Add a new Gantt object + function Add($aObject) { + if( is_array($aObject) && count($aObject) > 0 ) { + $cl = $aObject[0]; + if( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) { + $this->AddIcon($aObject); + } + elseif( class_exists('Text',false) && ($cl instanceof Text) ) { + $this->AddText($aObject); + } + else { + $n = count($aObject); + for($i=0; $i < $n; ++$i) + $this->iObj[] = $aObject[$i]; + } + } + else { + if( class_exists('IconPlot',false) && ($aObject instanceof IconPlot) ) { + $this->AddIcon($aObject); + } + elseif( class_exists('Text',false) && ($aObject instanceof Text) ) { + $this->AddText($aObject); + } + else { + $this->iObj[] = $aObject; + } + } + } + + function StrokeTexts() { + // Stroke any user added text objects + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i) { + if( $this->texts[$i]->iScalePosX !== null && $this->texts[$i]->iScalePosY !== null ) { + $x = $this->scale->TranslateDate($this->texts[$i]->iScalePosX); + $y = $this->scale->TranslateVertPos($this->texts[$i]->iScalePosY); + $y -= $this->scale->GetVertSpacing()/2; + } + else { + $x = $y = null; + } + $this->texts[$i]->Stroke($this->img,$x,$y); + } + } + } + + // Override inherit method from Graph and give a warning message + function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { + JpGraphError::RaiseL(6005); + //("SetScale() is not meaningfull with Gantt charts."); + } + + // Specify the date range for Gantt graphs (if this is not set it will be + // automtically determined from the input data) + function SetDateRange($aStart,$aEnd) { + // Adjust the start and end so that the indicate the + // begining and end of respective start and end days + if( strpos($aStart,':') === false ) + $aStart = date('Y-m-d 00:00',strtotime($aStart)); + if( strpos($aEnd,':') === false ) + $aEnd = date('Y-m-d 23:59',strtotime($aEnd)); + $this->scale->SetRange($aStart,$aEnd); + } + + // Get the maximum width of the activity titles columns for the bars + // The name is lightly misleading since we from now on can have + // multiple columns in the label section. When this was first written + // it only supported a single label, hence the name. + function GetMaxLabelWidth() { + $m=10; + if( $this->iObj != null ) { + $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin; + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + if( !empty($this->iObj[$i]->title) ) { + if( $this->iObj[$i]->title->HasTabs() ) { + list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); + $m=max($m,$tot); + } + else + $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); + } + } + } + return $m; + } + + // Get the maximum height of the titles for the bars + function GetMaxLabelHeight() { + $m=10; + if( $this->iObj != null ) { + $n = count($this->iObj); + // We can not include the title of GnttVLine since that title is stroked at the bottom + // of the Gantt bar and not in the activity title columns + for($i=0; $i < $n; ++$i) { + if( !empty($this->iObj[$i]->title) && !($this->iObj[$i] instanceof GanttVLine) ) { + $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); + } + } + } + return $m; + } + + function GetMaxBarAbsHeight() { + $m=0; + if( $this->iObj != null ) { + $m = $this->iObj[0]->GetAbsHeight($this->img); + $n = count($this->iObj); + for($i=1; $i < $n; ++$i) { + $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); + } + } + return $m; + } + + // Get the maximum used line number (vertical position) for bars + function GetBarMaxLineNumber() { + $m=1; + if( $this->iObj != null ) { + $m = $this->iObj[0]->GetLineNbr(); + $n = count($this->iObj); + for($i=1; $i < $n; ++$i) { + $m=max($m,$this->iObj[$i]->GetLineNbr()); + } + } + return $m; + } + + // Get the minumum and maximum used dates for all bars + function GetBarMinMax() { + $start = 0 ; + $n = count($this->iObj); + while( $start < $n && $this->iObj[$start]->GetMaxDate() === false ) + ++$start; + if( $start >= $n ) { + JpgraphError::RaiseL(6006); + //('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]'); + } + + $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate()); + $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate()); + + for($i=$start+1; $i < $n; ++$i) { + $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate()); + if( $rmax != false ) + $max=Max($max,$rmax); + $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate()); + if( $rmin != false ) + $min=Min($min,$rmin); + } + $minDate = date("Y-m-d",$min); + $min = strtotime($minDate); + $maxDate = date("Y-m-d 23:59",$max); + $max = strtotime($maxDate); + return array($min,$max); + } + + // Create a new auto sized canvas if the user hasn't specified a size + // The size is determined by what scale the user has choosen and hence + // the minimum width needed to display the headers. Some margins are + // also added to make it better looking. + function AutoSize() { + + if( $this->img->img == null ) { + // The predefined left, right, top, bottom margins. + // Note that the top margin might incease depending on + // the title. + $hadj = $vadj = 0; + if( $this->doshadow ) { + $hadj = $this->shadow_width; + $vadj = $this->shadow_width+5; + } + + $lm = $this->img->left_margin; + $rm = $this->img->right_margin +$hadj; + $rm += 2 ; + $tm = $this->img->top_margin; + $bm = $this->img->bottom_margin + $vadj; + $bm += 2; + + // If there are any added GanttVLine we must make sure that the + // bottom margin is wide enough to hold a title. + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + if( $this->iObj[$i] instanceof GanttVLine ) { + $bm = max($bm,$this->iObj[$i]->title->GetHeight($this->img)+10); + } + } + + // First find out the height + $n=$this->GetBarMaxLineNumber()+1; + $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); + $height=$n*((1+$this->iLabelVMarginFactor)*$m); + + // Add the height of the scale titles + $h=$this->scale->GetHeaderHeight(); + $height += $h; + + // Calculate the top margin needed for title and subtitle + if( $this->title->t != "" ) { + $tm += $this->title->GetFontHeight($this->img); + } + if( $this->subtitle->t != "" ) { + $tm += $this->subtitle->GetFontHeight($this->img); + } + + // ...and then take the bottom and top plot margins into account + $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; + // Now find the minimum width for the chart required + + // If day scale or smaller is shown then we use the day font width + // as the base size unit. + // If only weeks or above is displayed we use a modified unit to + // get a smaller image. + if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) { + // Add 2 pixel margin on each side + $fw=$this->scale->day->GetFontWidth($this->img)+4; + } + elseif( $this->scale->IsDisplayWeek() ) { + $fw = 8; + } + elseif( $this->scale->IsDisplayMonth() ) { + $fw = 4; + } + else { + $fw = 2; + } + + $nd=$this->scale->GetNumberOfDays(); + + if( $this->scale->IsDisplayDay() ) { + // If the days are displayed we also need to figure out + // how much space each day's title will require. + switch( $this->scale->day->iStyle ) { + case DAYSTYLE_LONG : + $txt = "Monday"; + break; + case DAYSTYLE_LONGDAYDATE1 : + $txt = "Monday 23 Jun"; + break; + case DAYSTYLE_LONGDAYDATE2 : + $txt = "Monday 23 Jun 2003"; + break; + case DAYSTYLE_SHORT : + $txt = "Mon"; + break; + case DAYSTYLE_SHORTDAYDATE1 : + $txt = "Mon 23/6"; + break; + case DAYSTYLE_SHORTDAYDATE2 : + $txt = "Mon 23 Jun"; + break; + case DAYSTYLE_SHORTDAYDATE3 : + $txt = "Mon 23"; + break; + case DAYSTYLE_SHORTDATE1 : + $txt = "23/6"; + break; + case DAYSTYLE_SHORTDATE2 : + $txt = "23 Jun"; + break; + case DAYSTYLE_SHORTDATE3 : + $txt = "Mon 23"; + break; + case DAYSTYLE_SHORTDATE4 : + $txt = "88"; + break; + case DAYSTYLE_CUSTOM : + $txt = date($this->scale->day->iLabelFormStr,strtotime('2003-12-20 18:00')); + break; + case DAYSTYLE_ONELETTER : + default: + $txt = "M"; + break; + } + $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6; + } + + // If we have hours enabled we must make sure that each day has enough + // space to fit the number of hours to be displayed. + if( $this->scale->IsDisplayHour() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->hour->iStyle ) { + case HOURSTYLE_HMAMPM: + $txt = '12:00pm'; + break; + case HOURSTYLE_H24: + // 13 + $txt = '24'; + break; + case HOURSTYLE_HAMPM: + $txt = '12pm'; + break; + case HOURSTYLE_CUSTOM: + $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00')); + break; + case HOURSTYLE_HM24: + default: + $txt = '24:00'; + break; + } + + $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6; + $mw = $hfw; + if( $this->scale->IsDisplayMinute() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->minute->iStyle ) { + case HOURSTYLE_CUSTOM: + $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); + break; + case MINUTESTYLE_MM: + default: + $txt2 = '15'; + break; + } + + $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6; + $n2 = ceil(60 / $this->scale->minute->GetIntervall() ); + $mw = $n2 * $mfw; + } + $hfw = $hfw < $mw ? $mw : $hfw ; + $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) ); + $hw = $n * $hfw; + $fw = $fw < $hw ? $hw : $fw ; + } + + // We need to repeat this code block here as well. + // THIS iS NOT A MISTAKE ! + // We really need it since we need to adjust for minutes both in the case + // where hour scale is shown and when it is not shown. + + if( $this->scale->IsDisplayMinute() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->minute->iStyle ) { + case HOURSTYLE_CUSTOM: + $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); + break; + case MINUTESTYLE_MM: + default: + $txt = '15'; + break; + } + + $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6; + $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) ); + $mw = $n * $mfw; + $fw = $fw < $mw ? $mw : $fw ; + } + + // If we display week we must make sure that 7*$fw is enough + // to fit up to 10 characters of the week font (if the week is enabled) + if( $this->scale->IsDisplayWeek() ) { + // Depending on what format the user has choose we need different amount + // of space + $fsw = strlen($this->scale->week->iLabelFormStr); + if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $fsw += 8; + } + elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) { + $fsw += 7; + } + else { + $fsw += 4; + } + + $ww = $fsw*$this->scale->week->GetFontWidth($this->img); + if( 7*$fw < $ww ) { + $fw = ceil($ww/7); + } + } + + if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() && + !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) { + // If we don't display the individual days we can shrink the + // scale a little bit. This is a little bit pragmatic at the + // moment and should be re-written to take into account + // a) What scales exactly are shown and + // b) what format do they use so we know how wide we need to + // make each scale text space at minimum. + $fw /= 2; + if( !$this->scale->IsDisplayWeek() ) { + $fw /= 1.8; + } + } + + $cw = $this->GetMaxActInfoColWidth() ; + $this->scale->actinfo->SetMinColWidth($cw); + if( $this->img->width <= 0 ) { + // Now determine the width for the activity titles column + + // Firdst find out the maximum width of each object column + $titlewidth = max(max($this->GetMaxLabelWidth(), + $this->scale->tableTitle->GetWidth($this->img)), + $this->scale->actinfo->GetWidth($this->img)); + + // Add the width of the vertivcal divider line + $titlewidth += $this->scale->divider->iWeight*2; + + // Adjust the width by the user specified zoom factor + $fw *= $this->iZoomFactor; + + // Now get the total width taking + // titlewidth, left and rigt margin, dayfont size + // into account + $width = $titlewidth + $nd*$fw + $lm+$rm; + } + else { + $width = $this->img->width; + } + + $width = round($width); + $height = round($height); + // Make a sanity check on image size + if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) { + JpgraphError::RaiseL(6007,$width,$height); + //("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities."); + } + $this->img->CreateImgCanvas($width,$height); + $this->img->SetMargin($lm,$rm,$tm,$bm); + } + } + + // Return an array width the maximum width for each activity + // column. This is used when we autosize the columns where we need + // to find out the maximum width of each column. In order to do that we + // must walk through all the objects, sigh... + function GetMaxActInfoColWidth() { + $n = count($this->iObj); + if( $n == 0 ) return; + $w = array(); + $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin; + + for( $i=0; $i < $n; ++$i ) { + $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m); + $nn = count($tmp); + for( $j=0; $j < $nn; ++$j ) { + if( empty($w[$j]) ) + $w[$j] = $tmp[$j]; + else + $w[$j] = max($w[$j],$tmp[$j]); + } + } + return $w; + } + + // Stroke the gantt chart + function Stroke($aStrokeFileName="") { + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // Should we autoscale dates? + + if( !$this->scale->IsRangeSet() ) { + list($min,$max) = $this->GetBarMinMax(); + $this->scale->SetRange($min,$max); + } + + $this->scale->AdjustStartEndDay(); + + // Check if we should autoscale the image + $this->AutoSize(); + + // Should we start from the top or just spread the bars out even over the + // available height + $this->scale->SetVertLayout($this->iLayout); + if( $this->iLayout == GANTT_FROMTOP ) { + $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); + $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); + } + // If it hasn't been set find out the maximum line number + if( $this->scale->iVertLines == -1 ) + $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; + + $maxwidth=max($this->scale->actinfo->GetWidth($this->img), + max($this->GetMaxLabelWidth(), + $this->scale->tableTitle->GetWidth($this->img))); + + $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor)); + + if( !$_csim ) { + $this->StrokePlotArea(); + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + } + + $this->scale->Stroke(); + + if( !$_csim ) { + // Due to a minor off by 1 bug we need to temporarily adjust the margin + $this->img->right_margin--; + $this->StrokePlotBox(); + $this->img->right_margin++; + } + + // Stroke Grid line + $this->hgrid->Stroke($this->img,$this->scale); + + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); + $this->iObj[$i]->Stroke($this->img,$this->scale); + } + + $this->StrokeTitles(); + + if( !$_csim ) { + $this->StrokeConstrains(); + $this->footer->Stroke($this->img); + + + if( $this->iIconDepth == DEPTH_FRONT) { + $this->StrokeIcons(); + } + + // Stroke all added user texts + $this->StrokeTexts(); + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + } + + function StrokeConstrains() { + $n = count($this->iObj); + + // Stroke all constrains + for($i=0; $i < $n; ++$i) { + + // Some gantt objects may not have constraints associated with them + // for example we can add IconPlots which doesn't have this property. + if( empty($this->iObj[$i]->constraints) ) continue; + + $numConstrains = count($this->iObj[$i]->constraints); + + for( $k = 0; $k < $numConstrains; $k++ ) { + $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow; + if( $vpos >= 0 ) { + $c1 = $this->iObj[$i]->iConstrainPos; + + // Find out which object is on the target row + $targetobj = -1; + for( $j=0; $j < $n && $targetobj == -1; ++$j ) { + if( $this->iObj[$j]->iVPos == $vpos ) { + $targetobj = $j; + } + } + if( $targetobj == -1 ) { + JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos); + //('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.'); + } + $c2 = $this->iObj[$targetobj]->iConstrainPos; + if( count($c1) == 4 && count($c2 ) == 4) { + switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) { + case CONSTRAIN_ENDSTART: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]); + } + else { + $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]); + } + $link->SetPath(3); + break; + case CONSTRAIN_STARTEND: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]); + } + else { + $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]); + } + $link->SetPath(0); + break; + case CONSTRAIN_ENDEND: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]); + } + else { + $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]); + } + $link->SetPath(1); + break; + case CONSTRAIN_STARTSTART: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]); + } + else { + $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]); + } + $link->SetPath(3); + break; + default: + JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos); + //('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos); + break; + } + + $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor); + $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize, + $this->iObj[$i]->constraints[$k]->iConstrainArrowType); + + $link->Stroke($this->img); + } + } + } + } + } + + function GetCSIMAreas() { + if( !$this->iHasStroked ) + $this->Stroke(_CSIM_SPECIALFILE); + + $csim = $this->title->GetCSIMAreas(); + $csim .= $this->subtitle->GetCSIMAreas(); + $csim .= $this->subsubtitle->GetCSIMAreas(); + + $n = count($this->iObj); + for( $i=$n-1; $i >= 0; --$i ) + $csim .= $this->iObj[$i]->GetCSIMArea(); + return $csim; + } +} + +//=================================================== +// CLASS PredefIcons +// Description: Predefined icons for use with Gantt charts +//=================================================== +define('GICON_WARNINGRED',0); +define('GICON_TEXT',1); +define('GICON_ENDCONS',2); +define('GICON_MAIL',3); +define('GICON_STARTCONS',4); +define('GICON_CALC',5); +define('GICON_MAGNIFIER',6); +define('GICON_LOCK',7); +define('GICON_STOP',8); +define('GICON_WARNINGYELLOW',9); +define('GICON_FOLDEROPEN',10); +define('GICON_FOLDER',11); +define('GICON_TEXTIMPORTANT',12); + +class PredefIcons { + private $iBuiltinIcon = null, $iLen = -1 ; + + function GetLen() { + return $this->iLen ; + } + + function GetImg($aIdx) { + if( $aIdx < 0 || $aIdx >= $this->iLen ) { + JpGraphError::RaiseL(6010,$aIdx); + //('Illegal icon index for Gantt builtin icon ['.$aIdx.']'); + } + return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1])); + } + + function __construct() { + //========================================================== + // warning.png + //========================================================== + $this->iBuiltinIcon[0][0]= 1043 ; + $this->iBuiltinIcon[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'. + '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'. + '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'. + 'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'. + 'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'. + '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'. + 'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'. + 'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'. + 'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'. + 'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'. + 'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'. + 'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'. + 'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ; + + //========================================================== + // edit.png + //========================================================== + $this->iBuiltinIcon[1][0]= 959 ; + $this->iBuiltinIcon[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'. + 'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'. + 'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'. + 'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'. + 'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'. + 'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'. + 'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'. + 'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'. + 'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'. + 'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'. + 'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'. + 'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ; + + //========================================================== + // endconstrain.png + //========================================================== + $this->iBuiltinIcon[2][0]= 666 ; + $this->iBuiltinIcon[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'. + 'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'. + 'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'. + 'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'. + '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'. + '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'. + 'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'. + 'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ; + + //========================================================== + // mail.png + //========================================================== + $this->iBuiltinIcon[3][0]= 1122 ; + $this->iBuiltinIcon[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'. + 'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'. + 'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'. + 'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'. + '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'. + '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'. + 'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'. + 'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'. + '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'. + 'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'. + 'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'. + 'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'. + 'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'. + 'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ; + + //========================================================== + // startconstrain.png + //========================================================== + $this->iBuiltinIcon[4][0]= 725 ; + $this->iBuiltinIcon[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'. + 'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'. + 'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'. + 'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'. + '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'. + 'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'. + 'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'. + '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'. + 'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ; + + //========================================================== + // calc.png + //========================================================== + $this->iBuiltinIcon[5][0]= 589 ; + $this->iBuiltinIcon[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'. + 'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'. + 'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'. + '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'. + 'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'. + 'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'. + 'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'. + 'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ; + + //========================================================== + // mag.png + //========================================================== + $this->iBuiltinIcon[6][0]= 1415 ; + $this->iBuiltinIcon[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'. + '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'. + 'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'. + 'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'. + 'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'. + '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'. + 'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'. + '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'. + 'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'. + 'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'. + 'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'. + 'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'. + 'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'. + 'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'. + 'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'. + 'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'. + 'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'. + 'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ; + + //========================================================== + // lock.png + //========================================================== + $this->iBuiltinIcon[7][0]= 963 ; + $this->iBuiltinIcon[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'. + 'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'. + 'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'. + 'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'. + 'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'. + 'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'. + 'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'. + 'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'. + 'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'. + 'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'. + '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'. + 'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ; + + //========================================================== + // stop.png + //========================================================== + $this->iBuiltinIcon[8][0]= 889 ; + $this->iBuiltinIcon[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'. + 'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'. + 'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'. + 'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'. + 'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'. + 'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'. + 'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'. + 'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'. + 'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'. + 'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'. + 'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ; + + //========================================================== + // error.png + //========================================================== + $this->iBuiltinIcon[9][0]= 541 ; + $this->iBuiltinIcon[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. + 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'. + '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'. + 'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'. + 'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'. + 'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'. + 'iOsCHgAAAABJRU5ErkJggg==' ; + + //========================================================== + // openfolder.png + //========================================================== + $this->iBuiltinIcon[10][0]= 2040 ; + $this->iBuiltinIcon[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'. + 'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'. + 'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'. + 'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'. + 'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'. + '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'. + 'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'. + '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'. + 'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'. + 'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'. + 'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'. + 'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'. + 'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'. + 'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'. + 'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'. + 'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'. + 'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'. + 'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'. + 'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'. + 'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'. + 'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'. + 'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'. + 'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'. + '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'. + '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'. + 'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'. + 'dBntAAAAAElFTkSuQmCC' ; + + //========================================================== + // folder.png + //========================================================== + $this->iBuiltinIcon[11][0]= 1824 ; + $this->iBuiltinIcon[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'. + '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'. + 'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'. + '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'. + 'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'. + 'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'. + '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'. + 'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'. + 'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'. + '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'. + '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'. + 'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'. + 'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'. + 'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'. + 'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'. + 'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'. + 'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'. + 'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'. + 'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'. + 'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'. + 'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'. + 'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'. + 'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'. + 'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ; + + //========================================================== + // file_important.png + //========================================================== + $this->iBuiltinIcon[12][0]= 1785 ; + $this->iBuiltinIcon[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'. + 'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'. + 'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'. + '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'. + 's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'. + 'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'. + 'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'. + 'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'. + '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'. + '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'. + 'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'. + 'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'. + 'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'. + 'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'. + 't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'. + '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'. + 'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'. + 'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'. + 'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'. + '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'. + 'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'. + 'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'. + '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ; + + $this->iLen = count($this->iBuiltinIcon); + } +} + +//=================================================== +// Global cache for builtin images +//=================================================== +$_gPredefIcons = new PredefIcons(); + +//=================================================== +// CLASS IconImage +// Description: Holds properties for an icon image +//=================================================== +class IconImage { + private $iGDImage=null; + private $iWidth,$iHeight; + private $ixalign='left',$iyalign='center'; + private $iScale=1.0; + + function __construct($aIcon,$aScale=1) { + GLOBAL $_gPredefIcons ; + if( is_string($aIcon) ) { + $this->iGDImage = Graph::LoadBkgImage('',$aIcon); + } + elseif( is_integer($aIcon) ) { + // Builtin image + $this->iGDImage = $_gPredefIcons->GetImg($aIcon); + } + else { + JpGraphError::RaiseL(6011); + //('Argument to IconImage must be string or integer'); + } + $this->iScale = $aScale; + $this->iWidth = Image::GetWidth($this->iGDImage); + $this->iHeight = Image::GetHeight($this->iGDImage); + } + + function GetWidth() { + return round($this->iScale*$this->iWidth); + } + + function GetHeight() { + return round($this->iScale*$this->iHeight); + } + + function SetAlign($aX='left',$aY='center') { + $this->ixalign = $aX; + $this->iyalign = $aY; + } + + function Stroke($aImg,$x,$y) { + + if( $this->ixalign == 'right' ) { + $x -= $this->iWidth; + } + elseif( $this->ixalign == 'center' ) { + $x -= round($this->iWidth/2*$this->iScale); + } + + if( $this->iyalign == 'bottom' ) { + $y -= $this->iHeight; + } + elseif( $this->iyalign == 'center' ) { + $y -= round($this->iHeight/2*$this->iScale); + } + + $aImg->Copy($this->iGDImage, + $x,$y,0,0, + round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale), + $this->iWidth,$this->iHeight); + } +} + + +//=================================================== +// CLASS TextProperty +// Description: Holds properties for a text +//=================================================== +class TextProperty { + public $iShow=true; + public $csimtarget='',$csimwintarget='',$csimalt=''; + private $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; + private $iFontArray=array(); + private $iColor="black"; + private $iText=""; + private $iHAlign="left",$iVAlign="bottom"; + + //--------------- + // CONSTRUCTOR + function __construct($aTxt='') { + $this->iText = $aTxt; + } + + //--------------- + // PUBLIC METHODS + function Set($aTxt) { + $this->iText = $aTxt; + } + + function SetCSIMTarget($aTarget,$aAltText='',$aWinTarget='') { + if( is_string($aTarget) ) + $aTarget = array($aTarget); + $this->csimtarget=$aTarget; + + if( is_string($aWinTarget) ) + $aWinTarget = array($aWinTarget); + $this->csimwintarget=$aWinTarget; + + if( is_string($aAltText) ) + $aAltText = array($aAltText); + $this->csimalt=$aAltText; + + } + + function SetCSIMAlt($aAltText) { + if( is_string($aAltText) ) + $aAltText = array($aAltText); + $this->csimalt=$aAltText; + } + + // Set text color + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function HasTabs() { + if( is_string($this->iText) ) { + return substr_count($this->iText,"\t") > 0; + } + elseif( is_array($this->iText) ) { + return false; + } + } + + // Get number of tabs in string + function GetNbrTabs() { + if( is_string($this->iText) ) { + return substr_count($this->iText,"\t") ; + } + else{ + return 0; + } + } + + // Set alignment + function Align($aHAlign,$aVAlign="bottom") { + $this->iHAlign=$aHAlign; + $this->iVAlign=$aVAlign; + } + + // Synonym + function SetAlign($aHAlign,$aVAlign="bottom") { + $this->iHAlign=$aHAlign; + $this->iVAlign=$aVAlign; + } + + // Specify font + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetColumnFonts($aFontArray) { + if( !is_array($aFontArray) || count($aFontArray[0]) != 3 ) { + JpGraphError::RaiseL(6033); + // 'Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)' + } + $this->iFontArray = $aFontArray; + } + + + function IsColumns() { + return is_array($this->iText) ; + } + + // Get width of text. If text contains several columns separated by + // tabs then return both the total width as well as an array with a + // width for each column. + function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { + $extra_margin=4; + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + if( is_string($this->iText) ) { + if( strlen($this->iText) == 0 ) return 0; + $tmp = preg_split('/\t/',$this->iText); + if( count($tmp) <= 1 || !$aUseTabs ) { + $w = $aImg->GetTextWidth($this->iText); + return $w + 2*$extra_margin; + } + else { + $tot=0; + $n = count($tmp); + for($i=0; $i < $n; ++$i) { + $res[$i] = $aImg->GetTextWidth($tmp[$i]); + $tot += $res[$i]*$aTabExtraMargin; + } + return array(round($tot),$res); + } + } + elseif( is_object($this->iText) ) { + // A single icon + return $this->iText->GetWidth()+2*$extra_margin; + } + elseif( is_array($this->iText) ) { + // Must be an array of texts. In this case we return the sum of the + // length + a fixed margin of 4 pixels on each text string + $n = count($this->iText); + $nf = count($this->iFontArray); + for( $i=0, $w=0; $i < $n; ++$i ) { + if( $i < $nf ) { + $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $tmp = $this->iText[$i]; + if( is_string($tmp) ) { + $w += $aImg->GetTextWidth($tmp)+$extra_margin; + } + else { + if( is_object($tmp) === false ) { + JpGraphError::RaiseL(6012); + } + $w += $tmp->GetWidth()+$extra_margin; + } + } + return $w; + } + else { + JpGraphError::RaiseL(6012); + } + } + + // for the case where we have multiple columns this function returns the width of each + // column individually. If there is no columns just return the width of the single + // column as an array of one + function GetColWidth($aImg,$aMargin=0) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + if( is_array($this->iText) ) { + $n = count($this->iText); + $nf = count($this->iFontArray); + for( $i=0, $w=array(); $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_string($tmp) ) { + if( $i < $nf ) { + $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $w[$i] = $aImg->GetTextWidth($tmp)+$aMargin; + } + else { + if( is_object($tmp) === false ) { + JpGraphError::RaiseL(6012); + } + $w[$i] = $tmp->GetWidth()+$aMargin; + } + } + return $w; + } + else { + return array($this->GetWidth($aImg)); + } + } + + // Get total height of text + function GetHeight($aImg) { + $nf = count($this->iFontArray); + $maxheight = -1; + + if( $nf > 0 ) { + // We have to find out the largest font and take that one as the + // height of the row + for($i=0; $i < $nf; ++$i ) { + $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]); + $height = $aImg->GetFontHeight(); + $maxheight = max($height,$maxheight); + } + } + + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $height = $aImg->GetFontHeight(); + $maxheight = max($height,$maxheight); + return $maxheight; + } + + // Unhide/hide the text + function Show($aShow=true) { + $this->iShow=$aShow; + } + + // Stroke text at (x,y) coordinates. If the text contains tabs then the + // x parameter should be an array of positions to be used for each successive + // tab mark. If no array is supplied then the tabs will be ignored. + function Stroke($aImg,$aX,$aY) { + if( $this->iShow ) { + $aImg->SetColor($this->iColor); + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); + if( $this->GetNbrTabs() < 1 ) { + if( is_string($this->iText) ) { + if( is_array($aX) ) $aX=$aX[0]; + if( is_array($aY) ) $aY=$aY[0]; + $aImg->StrokeText($aX,$aY,$this->iText); + } + elseif( is_array($this->iText) && ($n = count($this->iText)) > 0 ) { + $ax = is_array($aX) ; + $ay = is_array($aY) ; + if( $ax && $ay ) { + // Nothing; both are already arrays + } + elseif( $ax ) { + $aY = array_fill(0,$n,$aY); + } + elseif( $ay ) { + $aX = array_fill(0,$n,$aX); + } + else { + $aX = array_fill(0,$n,$aX); + $aY = array_fill(0,$n,$aY); + } + $n = min($n, count($aX) ) ; + $n = min($n, count($aY) ) ; + for($i=0; $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_object($tmp) ) { + $tmp->Stroke($aImg,$aX[$i],$aY[$i]); + } + else { + if( $i < count($this->iFontArray) ) { + $font = $this->iFontArray[$i]; + $aImg->SetFont($font[0],$font[1],$font[2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp)); + } + } + } + } + else { + $tmp = preg_split('/\t/',$this->iText); + $n = min(count($tmp),count($aX)); + for($i=0; $i < $n; ++$i) { + if( $i < count($this->iFontArray) ) { + $font = $this->iFontArray[$i]; + $aImg->SetFont($font[0],$font[1],$font[2]); + } + else { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + } + $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); + } + } + } + } +} + +//=================================================== +// CLASS HeaderProperty +// Description: Data encapsulating class to hold property +// for each type of the scale headers +//=================================================== +class HeaderProperty { + public $grid; + public $iShowLabels=true,$iShowGrid=true; + public $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; + public $iStyle=0; + public $iFrameColor="black",$iFrameWeight=1; + public $iBackgroundColor="white"; + public $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale + public $iTextColor="black"; + public $iLabelFormStr="%d"; + public $iIntervall = 1; + + //--------------- + // CONSTRUCTOR + function __construct() { + $this->grid = new LineProperty(); + } + + //--------------- + // PUBLIC METHODS + function Show($aShow=true) { + $this->iShowLabels = $aShow; + } + + function SetIntervall($aInt) { + $this->iIntervall = $aInt; + } + + function SetInterval($aInt) { + $this->iIntervall = $aInt; + } + + function GetIntervall() { + return $this->iIntervall ; + } + + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetFontColor($aColor) { + $this->iTextColor = $aColor; + } + + function GetFontHeight($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontHeight(); + } + + function GetFontWidth($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontWidth(); + } + + function GetStrWidth($aImg,$aStr) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetTextWidth($aStr); + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function SetBackgroundColor($aColor) { + $this->iBackgroundColor=$aColor; + } + + function SetFrameWeight($aWeight) { + $this->iFrameWeight=$aWeight; + } + + function SetFrameColor($aColor) { + $this->iFrameColor=$aColor; + } + + // Only used by day scale + function SetWeekendColor($aColor) { + $this->iWeekendBackgroundColor=$aColor; + } + + // Only used by day scale + function SetSundayFontColor($aColor) { + $this->iSundayTextColor=$aColor; + } + + function SetTitleVertMargin($aMargin) { + $this->iTitleVertMargin=$aMargin; + } + + function SetLabelFormatString($aStr) { + $this->iLabelFormStr=$aStr; + } + + function SetFormatString($aStr) { + $this->SetLabelFormatString($aStr); + } + + +} + +//=================================================== +// CLASS GanttScale +// Description: Responsible for calculating and showing +// the scale in a gantt chart. This includes providing methods for +// converting dates to position in the chart as well as stroking the +// date headers (days, week, etc). +//=================================================== +class GanttScale { + public $minute,$hour,$day,$week,$month,$year; + public $divider,$dividerh,$tableTitle; + public $iStartDate=-1,$iEndDate=-1; + // Number of gantt bar position (n.b not necessariliy the same as the number of bars) + // we could have on bar in position 1, and one bar in position 5 then there are two + // bars but the number of bar positions is 5 + public $actinfo; + public $iTopPlotMargin=10,$iBottomPlotMargin=15; + public $iVertLines=-1; + public $iVertHeaderSize=-1; + // The width of the labels (defaults to the widest of all labels) + private $iLabelWidth; + // Out image to stroke the scale to + private $iImg; + private $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; + private $iTableHeaderFrameWeight=1; + private $iAvailableHeight=-1,$iVertSpacing=-1; + private $iDateLocale; + private $iVertLayout=GANTT_EVEN; + private $iUsePlotWeekendBackground=true; + private $iWeekStart = 1; // Default to have weekends start on Monday + + //--------------- + // CONSTRUCTOR + function __construct($aImg) { + $this->iImg = $aImg; + $this->iDateLocale = new DateLocale(); + + $this->minute = new HeaderProperty(); + $this->minute->SetIntervall(15); + $this->minute->SetLabelFormatString('i'); + $this->minute->SetFont(FF_FONT0); + $this->minute->grid->SetColor("gray"); + + $this->hour = new HeaderProperty(); + $this->hour->SetFont(FF_FONT0); + $this->hour->SetIntervall(6); + $this->hour->SetStyle(HOURSTYLE_HM24); + $this->hour->SetLabelFormatString('H:i'); + $this->hour->grid->SetColor("gray"); + + $this->day = new HeaderProperty(); + $this->day->grid->SetColor("gray"); + $this->day->SetLabelFormatString('l'); + + $this->week = new HeaderProperty(); + $this->week->SetLabelFormatString("w%d"); + $this->week->SetFont(FF_FONT1); + + $this->month = new HeaderProperty(); + $this->month->SetFont(FF_FONT1,FS_BOLD); + + $this->year = new HeaderProperty(); + $this->year->SetFont(FF_FONT1,FS_BOLD); + + $this->divider=new LineProperty(); + $this->dividerh=new LineProperty(); + $this->dividerh->SetWeight(2); + $this->divider->SetWeight(6); + $this->divider->SetColor('gray'); + $this->divider->SetStyle('fancy'); + + $this->tableTitle=new TextProperty(); + $this->tableTitle->Show(false); + $this->actinfo = new GanttActivityInfo(); + } + + //--------------- + // PUBLIC METHODS + // Specify what headers should be visible + function ShowHeaders($aFlg) { + $this->day->Show($aFlg & GANTT_HDAY); + $this->week->Show($aFlg & GANTT_HWEEK); + $this->month->Show($aFlg & GANTT_HMONTH); + $this->year->Show($aFlg & GANTT_HYEAR); + $this->hour->Show($aFlg & GANTT_HHOUR); + $this->minute->Show($aFlg & GANTT_HMIN); + + // Make some default settings of gridlines whihc makes sense + if( $aFlg & GANTT_HWEEK ) { + $this->month->grid->Show(false); + $this->year->grid->Show(false); + } + if( $aFlg & GANTT_HHOUR ) { + $this->day->grid->SetColor("black"); + } + } + + // Should the weekend background stretch all the way down in the plotarea + function UseWeekendBackground($aShow) { + $this->iUsePlotWeekendBackground = $aShow; + } + + // Have a range been specified? + function IsRangeSet() { + return $this->iStartDate!=-1 && $this->iEndDate!=-1; + } + + // Should the layout be from top or even? + function SetVertLayout($aLayout) { + $this->iVertLayout = $aLayout; + } + + // Which locale should be used? + function SetDateLocale($aLocale) { + $this->iDateLocale->Set($aLocale); + } + + // Number of days we are showing + function GetNumberOfDays() { + return round(($this->iEndDate-$this->iStartDate)/SECPERDAY); + } + + // The width of the actual plot area + function GetPlotWidth() { + $img=$this->iImg; + return $img->width - $img->left_margin - $img->right_margin; + } + + // Specify the width of the titles(labels) for the activities + // (This is by default set to the minimum width enought for the + // widest title) + function SetLabelWidth($aLabelWidth) { + $this->iLabelWidth=$aLabelWidth; + } + + // Which day should the week start? + // 0==Sun, 1==Monday, 2==Tuesday etc + function SetWeekStart($aStartDay) { + $this->iWeekStart = $aStartDay % 7; + + //Recalculate the startday since this will change the week start + $this->SetRange($this->iStartDate,$this->iEndDate); + } + + // Do we show min scale? + function IsDisplayMinute() { + return $this->minute->iShowLabels; + } + + // Do we show day scale? + function IsDisplayHour() { + return $this->hour->iShowLabels; + } + + + // Do we show day scale? + function IsDisplayDay() { + return $this->day->iShowLabels; + } + + // Do we show week scale? + function IsDisplayWeek() { + return $this->week->iShowLabels; + } + + // Do we show month scale? + function IsDisplayMonth() { + return $this->month->iShowLabels; + } + + // Do we show year scale? + function IsDisplayYear() { + return $this->year->iShowLabels; + } + + // Specify spacing (in percent of bar height) between activity bars + function SetVertSpacing($aSpacing) { + $this->iVertSpacing = $aSpacing; + } + + // Specify scale min and max date either as timestamp or as date strings + // Always round to the nearest week boundary + function SetRange($aMin,$aMax) { + $this->iStartDate = $this->NormalizeDate($aMin); + $this->iEndDate = $this->NormalizeDate($aMax); + } + + + // Adjust the start and end date so they fit to beginning/ending + // of the week taking the specified week start day into account. + function AdjustStartEndDay() { + + if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) { + // Don't adjust + return; + } + + // Get day in week for start and ending date (Sun==0) + $ds=strftime("%w",$this->iStartDate); + $de=strftime("%w",$this->iEndDate); + + // We want to start on iWeekStart day. But first we subtract a week + // if the startdate is "behind" the day the week start at. + // This way we ensure that the given start date is always included + // in the range. If we don't do this the nearest correct weekday in the week + // to start at might be later than the start date. + if( $ds < $this->iWeekStart ) + $d = strtotime('-7 day',$this->iStartDate); + else + $d = $this->iStartDate; + $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ ); + $this->iStartDate = $adjdate; + + // We want to end on the last day of the week + $preferredEndDay = ($this->iWeekStart+6)%7; + if( $preferredEndDay != $de ) { + // Solve equivalence eq: $de + x ~ $preferredDay (mod 7) + $adj = (7+($preferredEndDay - $de)) % 7; + $adjdate = strtotime("+$adj day",$this->iEndDate); + $this->iEndDate = $adjdate; + } + } + + // Specify background for the table title area (upper left corner of the table) + function SetTableTitleBackground($aColor) { + $this->iTableHeaderBackgroundColor = $aColor; + } + + /////////////////////////////////////// + // PRIVATE Methods + + // Determine the height of all the scale headers combined + function GetHeaderHeight() { + $img=$this->iImg; + $height=1; + if( $this->minute->iShowLabels ) { + $height += $this->minute->GetFontHeight($img); + $height += $this->minute->iTitleVertMargin; + } + if( $this->hour->iShowLabels ) { + $height += $this->hour->GetFontHeight($img); + $height += $this->hour->iTitleVertMargin; + } + if( $this->day->iShowLabels ) { + $height += $this->day->GetFontHeight($img); + $height += $this->day->iTitleVertMargin; + } + if( $this->week->iShowLabels ) { + $height += $this->week->GetFontHeight($img); + $height += $this->week->iTitleVertMargin; + } + if( $this->month->iShowLabels ) { + $height += $this->month->GetFontHeight($img); + $height += $this->month->iTitleVertMargin; + } + if( $this->year->iShowLabels ) { + $height += $this->year->GetFontHeight($img); + $height += $this->year->iTitleVertMargin; + } + return $height; + } + + // Get width (in pixels) for a single day + function GetDayWidth() { + return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); + } + + // Get width (in pixels) for a single hour + function GetHourWidth() { + return $this->GetDayWidth() / 24 ; + } + + function GetMinuteWidth() { + return $this->GetHourWidth() / 60 ; + } + + // Nuber of days in a year + function GetNumDaysInYear($aYear) { + if( $this->IsLeap($aYear) ) + return 366; + else + return 365; + } + + // Get week number + function GetWeekNbr($aDate,$aSunStart=true) { + // We can't use the internal strftime() since it gets the weeknumber + // wrong since it doesn't follow ISO on all systems since this is + // system linrary dependent. + // Even worse is that this works differently if we are on a Windows + // or UNIX box (it even differs between UNIX boxes how strftime() + // is natively implemented) + // + // Credit to Nicolas Hoizey for this elegant + // version of Week Nbr calculation. + + $day = $this->NormalizeDate($aDate); + if( $aSunStart ) + $day += 60*60*24; + + /*------------------------------------------------------------------------- + According to ISO-8601 : + "Week 01 of a year is per definition the first week that has the Thursday in this year, + which is equivalent to the week that contains the fourth day of January. + In other words, the first week of a new year is the week that has the majority of its + days in the new year." + + Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! + + day of year = date("z", $day) + 1 + offset to thursday = 3 - (date("w", $day) + 6) % 7 + first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 + week number = (thursday's day of year - first thursday's day of year) / 7 + 1 + ---------------------------------------------------------------------------*/ + + $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday + $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; + + return $week; + } + + // Is year a leap year? + function IsLeap($aYear) { + // Is the year a leap year? + //$year = 0+date("Y",$aDate); + if( $aYear % 4 == 0) + if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) + return true; + return false; + } + + // Get current year + function GetYear($aDate) { + return 0+Date("Y",$aDate); + } + + // Return number of days in a year + function GetNumDaysInMonth($aMonth,$aYear) { + $days=array(31,28,31,30,31,30,31,31,30,31,30,31); + $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); + if( $this->IsLeap($aYear)) + return $daysl[$aMonth]; + else + return $days[$aMonth]; + } + + // Get day in month + function GetMonthDayNbr($aDate) { + return 0+strftime("%d",$aDate); + } + + // Get day in year + function GetYearDayNbr($aDate) { + return 0+strftime("%j",$aDate); + } + + // Get month number + function GetMonthNbr($aDate) { + return 0+strftime("%m",$aDate); + } + + // Translate a date to screen coordinates (horizontal scale) + function TranslateDate($aDate) { + // + // In order to handle the problem with Daylight savings time + // the scale written with equal number of seconds per day beginning + // with the start date. This means that we "cement" the state of + // DST as it is in the start date. If later the scale includes the + // switchover date (depends on the locale) we need to adjust back + // if the date we try to translate has a different DST status since + // we would otherwise be off by one hour. + $aDate = $this->NormalizeDate($aDate); + $tmp = localtime($aDate); + $cloc = $tmp[8]; + $tmp = localtime($this->iStartDate); + $sloc = $tmp[8]; + $offset = 0; + if( $sloc != $cloc) { + if( $sloc ) + $offset = 3600; + else + $offset = -3600; + } + $img=$this->iImg; + return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; + } + + // Get screen coordinatesz for the vertical position for a bar + function TranslateVertPos($aPos,$atTop=false) { + $img=$this->iImg; + if( $aPos > $this->iVertLines ) + JpGraphError::RaiseL(6015,$aPos); + // 'Illegal vertical position %d' + if( $this->iVertLayout == GANTT_EVEN ) { + // Position the top bar at 1 vert spacing from the scale + $pos = round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); + } + else { + // position the top bar at 1/2 a vert spacing from the scale + $pos = round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); + } + + if( $atTop ) + $pos -= $this->iVertSpacing; + + return $pos; + } + + // What is the vertical spacing? + function GetVertSpacing() { + return $this->iVertSpacing; + } + + // Convert a date to timestamp + function NormalizeDate($aDate) { + if( $aDate === false ) return false; + if( is_string($aDate) ) { + $t = strtotime($aDate); + if( $t === FALSE || $t === -1 ) { + JpGraphError::RaiseL(6016,$aDate); + //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30"); + } + return $t; + } + elseif( is_int($aDate) || is_float($aDate) ) + return $aDate; + else + JpGraphError::RaiseL(6017,$aDate); + //Unknown date format in GanttScale ($aDate)."); + } + + + // Convert a time string to minutes + + function TimeToMinutes($aTimeString) { + // Split in hours and minutes + $pos=strpos($aTimeString,':'); + $minint=60; + if( $pos === false ) { + $hourint = $aTimeString; + $minint = 0; + } + else { + $hourint = floor(substr($aTimeString,0,$pos)); + $minint = floor(substr($aTimeString,$pos+1)); + } + $minint += 60 * $hourint; + return $minint; + } + + // Stroke the day scale (including gridlines) + function StrokeMinutes($aYCoord,$getHeight=false) { + $img=$this->iImg; + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->minute->iShowLabels ) { + $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize); + $yb = $yt + $img->GetFontHeight() + + $this->minute->iTitleVertMargin + $this->minute->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb = $img->width-$img->right_margin+1; + $img->SetColor($this->minute->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $day = date('w',$this->iStartDate); + $minint = $this->minute->GetIntervall() ; + + if( 60 % $minint !== 0 ) { + JpGraphError::RaiseL(6018,$minint); + //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.'); + } + + + $n = 60 / $minint; + $datestamp = $this->iStartDate; + $width = $this->GetHourWidth() / $n ; + if( $width < 8 ) { + // TO small width to draw minute scale + JpGraphError::RaiseL(6019,$width); + //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.'); + } + + $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) ); + $nd = $this->GetNumberOfDays(); + // Convert to intervall to seconds + $minint *= 60; + for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) { + for( $k=0; $k < $nh; ++$k ) { + for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) { + if( $day==6 || $day==0 ) { + + $img->PushColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground ) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); + $img->PopColor(); + + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + + switch( $this->minute->iStyle ) { + case MINUTESTYLE_CUSTOM: + $txt = date($this->minute->iLabelFormStr,$datestamp); + break; + case MINUTESTYLE_MM: + default: + // 15 + $txt = date('i',$datestamp); + break; + } + $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt); + + // Fix a rounding problem the wrong way .. + // If we also have hour scale then don't draw the firsta or last + // gridline since that will be overwritten by the hour scale gridline if such exists. + // However, due to the propagation of rounding of the 'x+=width' term in the loop + // this might sometimes be one pixel of so we fix this by not drawing it. + // The proper way to fix it would be to re-calculate the scale for each step and + // not using the additive term. + if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) { + $img->SetColor($this->minute->grid->iColor); + $img->SetLineWeight($this->minute->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + } + } + } + } + $img->SetColor($this->minute->iFrameColor); + $img->SetLineWeight($this->minute->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + // Stroke the day scale (including gridlines) + function StrokeHours($aYCoord,$getHeight=false) { + $img=$this->iImg; + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->hour->iShowLabels ) { + $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize); + $yb = $yt + $img->GetFontHeight() + + $this->hour->iTitleVertMargin + $this->hour->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb = $img->width-$img->right_margin+1; + $img->SetColor($this->hour->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $tmp = $this->hour->GetIntervall() ; + $minint = $this->TimeToMinutes($tmp); + if( 1440 % $minint !== 0 ) { + JpGraphError::RaiseL(6020,$tmp); + //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp); + } + + $n = ceil(24*60 / $minint ); + $datestamp = $this->iStartDate; + $day = date('w',$this->iStartDate); + $doback = !$this->minute->iShowLabels; + $width = $this->GetDayWidth() / $n ; + for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) { + for($i=0; $i < $n ;++$i, $x+=$width) { + if( $day==6 || $day==0 ) { + + $img->PushColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground && $doback ) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); + $img->PopColor(); + + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + + switch( $this->hour->iStyle ) { + case HOURSTYLE_HMAMPM: + // 1:35pm + $txt = date('g:ia',$datestamp); + break; + case HOURSTYLE_H24: + // 13 + $txt = date('H',$datestamp); + break; + case HOURSTYLE_HAMPM: + $txt = date('ga',$datestamp); + break; + case HOURSTYLE_CUSTOM: + $txt = date($this->hour->iLabelFormStr,$datestamp); + break; + case HOURSTYLE_HM24: + default: + $txt = date('H:i',$datestamp); + break; + } + $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt); + $img->SetColor($this->hour->grid->iColor); + $img->SetLineWeight($this->hour->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + //$datestamp += $minint*60 + $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0, + date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); + + } + } + $img->SetColor($this->hour->iFrameColor); + $img->SetLineWeight($this->hour->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + + // Stroke the day scale (including gridlines) + function StrokeDays($aYCoord,$getHeight=false) { + $img=$this->iImg; + $daywidth=$this->GetDayWidth(); + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->day->iShowLabels ) { + $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb=$img->width-$img->right_margin+1; + $img->SetColor($this->day->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $day = date('w',$this->iStartDate); + $datestamp = $this->iStartDate; + + $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels); + + setlocale(LC_TIME,$this->iDateLocale->iLocale); + + for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) { + if( $day==6 || $day==0 ) { + $img->SetColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground && $doback) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, + $x+$daywidth,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, + $x+$daywidth,$yb-$this->day->iFrameWeight); + } + + $mn = strftime('%m',$datestamp); + if( $mn[0]=='0' ) + $mn = $mn[1]; + + switch( $this->day->iStyle ) { + case DAYSTYLE_LONG: + // "Monday" + $txt = strftime('%A',$datestamp); + break; + case DAYSTYLE_SHORT: + // "Mon" + $txt = strftime('%a',$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE1: + // "Mon 23/6" + $txt = strftime('%a %d/'.$mn,$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE2: + // "Mon 23 Jun" + $txt = strftime('%a %d %b',$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE3: + // "Mon 23 Jun 2003" + $txt = strftime('%a %d %b %Y',$datestamp); + break; + case DAYSTYLE_LONGDAYDATE1: + // "Monday 23 Jun" + $txt = strftime('%A %d %b',$datestamp); + break; + case DAYSTYLE_LONGDAYDATE2: + // "Monday 23 Jun 2003" + $txt = strftime('%A %d %b %Y',$datestamp); + break; + case DAYSTYLE_SHORTDATE1: + // "23/6" + $txt = strftime('%d/'.$mn,$datestamp); + break; + case DAYSTYLE_SHORTDATE2: + // "23 Jun" + $txt = strftime('%d %b',$datestamp); + break; + case DAYSTYLE_SHORTDATE3: + // "Mon 23" + $txt = strftime('%a %d',$datestamp); + break; + case DAYSTYLE_SHORTDATE4: + // "23" + $txt = strftime('%d',$datestamp); + break; + case DAYSTYLE_CUSTOM: + // Custom format + $txt = strftime($this->day->iLabelFormStr,$datestamp); + break; + case DAYSTYLE_ONELETTER: + default: + // "M" + $txt = strftime('%A',$datestamp); + $txt = strtoupper($txt[0]); + break; + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + $img->StrokeText(round($x+$daywidth/2+1), + round($yb-$this->day->iTitleVertMargin),$txt); + $img->SetColor($this->day->grid->iColor); + $img->SetLineWeight($this->day->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); + //$datestamp += SECPERDAY; + + } + $img->SetColor($this->day->iFrameColor); + $img->SetLineWeight($this->day->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + // Stroke week header and grid + function StrokeWeeks($aYCoord,$getHeight=false) { + if( $this->week->iShowLabels ) { + $img=$this->iImg; + $yt=$aYCoord+$img->top_margin; + $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; + + if( $getHeight ) { + return $yb - $img->top_margin; + } + + $xt=$img->left_margin+$this->iLabelWidth; + $weekwidth=$this->GetDayWidth()*7; + $wdays=$this->iDateLocale->GetDayAbb(); + $xb=$img->width-$img->right_margin+1; + $week = $this->iStartDate; + $weeknbr=$this->GetWeekNbr($week); + $img->SetColor($this->week->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $img->SetColor($this->week->grid->iColor); + $x = $xt; + if( $this->week->iStyle==WEEKSTYLE_WNBR ) { + $img->SetTextAlign("center"); + $txtOffset = $weekwidth/2+1; + } + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || + $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $img->SetTextAlign("left"); + $txtOffset = 3; + } + else { + JpGraphError::RaiseL(6021); + //("Unknown formatting style for week."); + } + + for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { + $img->PushColor($this->week->iTextColor); + + if( $this->week->iStyle==WEEKSTYLE_WNBR ) + $txt = sprintf($this->week->iLabelFormStr,$weeknbr); + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || + $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) + $txt = date("j/n",$week); + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $monthnbr = date("n",$week)-1; + $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); + $txt = Date("j",$week)." ".$shortmonth; + } + + if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $w = sprintf($this->week->iLabelFormStr,$weeknbr); + $txt .= ' '.$w; + } + + $img->StrokeText(round($x+$txtOffset), + round($yb-$this->week->iTitleVertMargin),$txt); + + $week = strtotime('+7 day',$week); + $weeknbr = $this->GetWeekNbr($week); + $img->PopColor(); + $img->SetLineWeight($this->week->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + } + $img->SetColor($this->week->iFrameColor); + $img->SetLineWeight($this->week->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Format the mont scale header string + function GetMonthLabel($aMonthNbr,$year) { + $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); + $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); + switch($this->month->iStyle) { + case MONTHSTYLE_SHORTNAME: + $m=$sn; + break; + case MONTHSTYLE_LONGNAME: + $m=$ln; + break; + case MONTHSTYLE_SHORTNAMEYEAR2: + $m=$sn." '".substr("".$year,2); + break; + case MONTHSTYLE_SHORTNAMEYEAR4: + $m=$sn." ".$year; + break; + case MONTHSTYLE_LONGNAMEYEAR2: + $m=$ln." '".substr("".$year,2); + break; + case MONTHSTYLE_LONGNAMEYEAR4: + $m=$ln." ".$year; + break; + case MONTHSTYLE_FIRSTLETTER: + $m=$sn[0]; + break; + } + return $m; + } + + // Stroke month scale and gridlines + function StrokeMonths($aYCoord,$getHeight=false) { + if( $this->month->iShowLabels ) { + $img=$this->iImg; + $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); + $yt=$aYCoord+$img->top_margin; + $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; + $xt=$img->left_margin+$this->iLabelWidth; + $xb=$img->width-$img->right_margin+1; + + $img->SetColor($this->month->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $img->SetLineWeight($this->month->grid->iWeight); + $img->SetColor($this->month->iTextColor); + $year = 0+strftime("%Y",$this->iStartDate); + $img->SetTextAlign("center"); + if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) + && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) { + $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1); + } + else { + $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); + } + // Is it enough space to stroke the first month? + $monthName = $this->GetMonthLabel($monthnbr,$year); + if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { + $img->SetColor($this->month->iTextColor); + $img->StrokeText(round($xt+$monthwidth/2+1), + round($yb-$this->month->iTitleVertMargin), + $monthName); + } + $x = $xt + $monthwidth; + while( $x < $xb ) { + $img->SetColor($this->month->grid->iColor); + $img->Line($x,$yt,$x,$yb); + $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $monthnbr++; + if( $monthnbr==12 ) { + $monthnbr=0; + $year++; + } + $monthName = $this->GetMonthLabel($monthnbr,$year); + $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); + if( $x + $monthwidth < $xb ) + $w = $monthwidth; + else + $w = $xb-$x; + if( $w >= 1.2*$img->GetTextWidth($monthName) ) { + $img->SetColor($this->month->iTextColor); + $img->StrokeText(round($x+$w/2+1), + round($yb-$this->month->iTitleVertMargin),$monthName); + } + $x += $monthwidth; + } + $img->SetColor($this->month->iFrameColor); + $img->SetLineWeight($this->month->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Stroke year scale and gridlines + function StrokeYears($aYCoord,$getHeight=false) { + if( $this->year->iShowLabels ) { + $img=$this->iImg; + $yt=$aYCoord+$img->top_margin; + $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; + + if( $getHeight ) { + return $yb - $img->top_margin; + } + + $xb=$img->width-$img->right_margin+1; + $xt=$img->left_margin+$this->iLabelWidth; + $year = $this->GetYear($this->iStartDate); + $img->SetColor($this->year->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $img->SetLineWeight($this->year->grid->iWeight); + $img->SetTextAlign("center"); + if( $year == $this->GetYear($this->iEndDate) ) + $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); + else + $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); + + // The space for a year must be at least 20% bigger than the actual text + // so we allow 10% margin on each side + if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { + $img->SetColor($this->year->iTextColor); + $img->StrokeText(round($xt+$yearwidth/2+1), + round($yb-$this->year->iTitleVertMargin), + $year); + } + $x = $xt + $yearwidth; + while( $x < $xb ) { + $img->SetColor($this->year->grid->iColor); + $img->Line($x,$yt,$x,$yb); + $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $year += 1; + $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); + if( $x + $yearwidth < $xb ) + $w = $yearwidth; + else + $w = $xb-$x; + if( $w >= 1.2*$img->GetTextWidth("".$year) ) { + $img->SetColor($this->year->iTextColor); + $img->StrokeText(round($x+$w/2+1), + round($yb-$this->year->iTitleVertMargin), + $year); + } + $x += $yearwidth; + } + $img->SetColor($this->year->iFrameColor); + $img->SetLineWeight($this->year->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Stroke table title (upper left corner) + function StrokeTableHeaders($aYBottom) { + $img=$this->iImg; + $xt=$img->left_margin; + $yt=$img->top_margin; + $xb=$xt+$this->iLabelWidth; + $yb=$aYBottom+$img->top_margin; + + if( $this->tableTitle->iShow ) { + $img->SetColor($this->iTableHeaderBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $this->tableTitle->Align("center","top"); + $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2); + $img->SetColor($this->iTableHeaderFrameColor); + $img->SetLineWeight($this->iTableHeaderFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + } + + $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow); + + + // Draw the horizontal dividing line + $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); + + // Draw the vertical dividing line + // We do the width "manually" since we want the line only to grow + // to the left + $fancy = $this->divider->iStyle == 'fancy' ; + if( $fancy ) { + $this->divider->iStyle = 'solid'; + } + + $tmp = $this->divider->iWeight; + $this->divider->iWeight=1; + $y = $img->height-$img->bottom_margin; + for($i=0; $i < $tmp; ++$i ) { + $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y); + } + + // Should we draw "fancy" divider + if( $fancy ) { + $img->SetLineWeight(1); + $img->SetColor($this->iTableHeaderFrameColor); + $img->Line($xb,$yt,$xb,$y); + $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y); + $img->SetColor('white'); + $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y); + } + } + + // Main entry point to stroke scale + function Stroke() { + if( !$this->IsRangeSet() ) { + JpGraphError::RaiseL(6022); + //("Gantt scale has not been specified."); + } + $img=$this->iImg; + + // If minutes are displayed then hour interval must be 1 + if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) { + JpGraphError::RaiseL(6023); + //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).'); + } + + // Stroke all headers. As argument we supply the offset from the + // top which depends on any previous headers + + // First find out the height of each header + $offy=$this->StrokeYears(0,true); + $offm=$this->StrokeMonths($offy,true); + $offw=$this->StrokeWeeks($offm,true); + $offd=$this->StrokeDays($offw,true); + $offh=$this->StrokeHours($offd,true); + $offmin=$this->StrokeMinutes($offh,true); + + + // ... then we can stroke them in the "backwards order to ensure that + // the larger scale gridlines is stroked over the smaller scale gridline + $this->StrokeMinutes($offh); + $this->StrokeHours($offd); + $this->StrokeDays($offw); + $this->StrokeWeeks($offm); + $this->StrokeMonths($offy); + $this->StrokeYears(0); + + // Now when we now the oaverall size of the scale headers + // we can stroke the overall table headers + $this->StrokeTableHeaders($offmin); + + // Now we can calculate the correct scaling factor for each vertical position + $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; + + $this->iVertHeaderSize = $offmin; + if( $this->iVertSpacing == -1 ) + $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; + } +} + + +//=================================================== +// CLASS GanttConstraint +// Just a structure to store all the values for a constraint +//=================================================== +class GanttConstraint { + public $iConstrainRow; + public $iConstrainType; + public $iConstrainColor; + public $iConstrainArrowSize; + public $iConstrainArrowType; + + //--------------- + // CONSTRUCTOR + function __construct($aRow,$aType,$aColor,$aArrowSize,$aArrowType){ + $this->iConstrainType = $aType; + $this->iConstrainRow = $aRow; + $this->iConstrainColor=$aColor; + $this->iConstrainArrowSize=$aArrowSize; + $this->iConstrainArrowType=$aArrowType; + } +} + + +//=================================================== +// CLASS GanttPlotObject +// The common signature for a Gantt object +//=================================================== +class GanttPlotObject { + public $title,$caption; + public $csimarea='',$csimtarget='',$csimwintarget='',$csimalt=''; + public $constraints = array(); + public $iCaptionMargin=5; + public $iConstrainPos=array(); + protected $iStart=""; // Start date + public $iVPos=0; // Vertical position + protected $iLabelLeftMargin=2; // Title margin + + function __construct() { + $this->title = new TextProperty(); + $this->title->Align('left','center'); + $this->caption = new TextProperty(); + } + + function GetCSIMArea() { + return $this->csimarea; + } + + function SetCSIMTarget($aTarget,$aAlt='',$aWinTarget='') { + if( !is_string($aTarget) ) { + $tv = substr(var_export($aTarget,true),0,40); + JpGraphError::RaiseL(6024,$tv); + //('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv"); + } + if( !is_string($aAlt) ) { + $tv = substr(var_export($aAlt,true),0,40); + JpGraphError::RaiseL(6025,$tv); + //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); + } + + $this->csimtarget=$aTarget; + $this->csimwintarget=$aWinTarget; + $this->csimalt=$aAlt; + } + + function SetCSIMAlt($aAlt) { + if( !is_string($aAlt) ) { + $tv = substr(var_export($aAlt,true),0,40); + JpGraphError::RaiseL(6025,$tv); + //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); + } + $this->csimalt=$aAlt; + } + + function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) { + $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType); + } + + function SetConstrainPos($xt,$yt,$xb,$yb) { + $this->iConstrainPos = array($xt,$yt,$xb,$yb); + } + + function GetMinDate() { + return $this->iStart; + } + + function GetMaxDate() { + return $this->iStart; + } + + function SetCaptionMargin($aMarg) { + $this->iCaptionMargin=$aMarg; + } + + function GetAbsHeight($aImg) { + return 0; + } + + function GetLineNbr() { + return $this->iVPos; + } + + function SetLabelLeftMargin($aOff) { + $this->iLabelLeftMargin=$aOff; + } + + function StrokeActInfo($aImg,$aScale,$aYPos) { + $cols=array(); + $aScale->actinfo->GetColStart($aImg,$cols,true); + $this->title->Stroke($aImg,$cols,$aYPos); + } +} + +//=================================================== +// CLASS Progress +// Holds parameters for the progress indicator +// displyed within a bar +//=================================================== +class Progress { + public $iProgress=-1; + public $iPattern=GANTT_SOLID; + public $iColor="black", $iFillColor='black'; + public $iDensity=98, $iHeight=0.65; + + function Set($aProg) { + if( $aProg < 0.0 || $aProg > 1.0 ) { + JpGraphError::RaiseL(6027); + //("Progress value must in range [0, 1]"); + } + $this->iProgress = $aProg; + } + + function SetPattern($aPattern,$aColor="blue",$aDensity=98) { + $this->iPattern = $aPattern; + $this->iColor = $aColor; + $this->iDensity = $aDensity; + } + + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + function SetHeight($aHeight) { + $this->iHeight = $aHeight; + } +} + +define('GANTT_HGRID1',0); +define('GANTT_HGRID2',1); + +//=================================================== +// CLASS HorizontalGridLine +// Responsible for drawinf horizontal gridlines and filled alternatibg rows +//=================================================== +class HorizontalGridLine { + private $iGraph=NULL; + private $iRowColor1 = '', $iRowColor2 = ''; + private $iShow=false; + private $line=null; + private $iStart=0; // 0=from left margin, 1=just along header + + function __construct() { + $this->line = new LineProperty(); + $this->line->SetColor('gray@0.4'); + $this->line->SetStyle('dashed'); + } + + function Show($aShow=true) { + $this->iShow = $aShow; + } + + function SetRowFillColor($aColor1,$aColor2='') { + $this->iRowColor1 = $aColor1; + $this->iRowColor2 = $aColor2; + } + + function SetStart($aStart) { + $this->iStart = $aStart; + } + + function Stroke($aImg,$aScale) { + + if( ! $this->iShow ) return; + + // Get horizontal width of line + /* + $limst = $aScale->iStartDate; + $limen = $aScale->iEndDate; + $xt = round($aScale->TranslateDate($aScale->iStartDate)); + $xb = round($aScale->TranslateDate($limen)); + */ + + if( $this->iStart === 0 ) { + $xt = $aImg->left_margin-1; + } + else { + $xt = round($aScale->TranslateDate($aScale->iStartDate))+1; + } + + $xb = $aImg->width-$aImg->right_margin; + + $yt = round($aScale->TranslateVertPos(0)); + $yb = round($aScale->TranslateVertPos(1)); + $height = $yb - $yt; + + // Loop around for all lines in the chart + for($i=0; $i < $aScale->iVertLines; ++$i ) { + $yb = $yt - $height; + $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); + if( $this->iRowColor1 !== '' ) { + if( $i % 2 == 0 ) { + $aImg->PushColor($this->iRowColor1); + $aImg->FilledRectangle($xt,$yt,$xb,$yb); + $aImg->PopColor(); + } + elseif( $this->iRowColor2 !== '' ) { + $aImg->PushColor($this->iRowColor2); + $aImg->FilledRectangle($xt,$yt,$xb,$yb); + $aImg->PopColor(); + } + } + $yt = round($aScale->TranslateVertPos($i+1)); + } + $yb = $yt - $height; + $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); + } +} + + +//=================================================== +// CLASS GanttBar +// Responsible for formatting individual gantt bars +//=================================================== +class GanttBar extends GanttPlotObject { + public $progress; + public $leftMark,$rightMark; + private $iEnd; + private $iHeightFactor=0.5; + private $iFillColor="white",$iFrameColor="black"; + private $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; + private $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; + private $iBreakStyle=false, $iBreakLineStyle='dotted',$iBreakLineWeight=1; + //--------------- + // CONSTRUCTOR + function __construct($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { + parent::__construct(); + $this->iStart = $aStart; + // Is the end date given as a date or as number of days added to start date? + if( is_string($aEnd) ) { + // If end date has been specified without a time we will asssume + // end date is at the end of that date + if( strpos($aEnd,':') === false ) { + $this->iEnd = strtotime($aEnd)+SECPERDAY-1; + } + else { + $this->iEnd = $aEnd; + } + } + elseif(is_int($aEnd) || is_float($aEnd) ) { + $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); + } + $this->iVPos = $aPos; + $this->iHeightFactor = $aHeightFactor; + $this->title->Set($aLabel); + $this->caption = new TextProperty($aCaption); + $this->caption->Align("left","center"); + $this->leftMark =new PlotMark(); + $this->leftMark->Hide(); + $this->rightMark=new PlotMark(); + $this->rightMark->Hide(); + $this->progress = new Progress(); + } + + //--------------- + // PUBLIC METHODS + function SetShadow($aShadow=true,$aColor="gray") { + $this->iShadow=$aShadow; + $this->iShadowColor=$aColor; + } + + function SetBreakStyle($aFlg=true,$aLineStyle='dotted',$aLineWeight=1) { + $this->iBreakStyle = $aFlg; + $this->iBreakLineStyle = $aLineStyle; + $this->iBreakLineWeight = $aLineWeight; + } + + function GetMaxDate() { + return $this->iEnd; + } + + function SetHeight($aHeight) { + $this->iHeightFactor = $aHeight; + } + + function SetColor($aColor) { + $this->iFrameColor = $aColor; + } + + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + function GetAbsHeight($aImg) { + if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { + $m=-1; + if( is_int($this->iHeightFactor) ) + $m = $this->iHeightFactor; + if( $this->leftMark->show ) + $m = max($m,$this->leftMark->width*2); + if( $this->rightMark->show ) + $m = max($m,$this->rightMark->width*2); + return $m; + } + else + return -1; + } + + function SetPattern($aPattern,$aColor="blue",$aDensity=95) { + $this->iPattern = $aPattern; + $this->iPatternColor = $aColor; + $this->iPatternDensity = $aDensity; + } + + function Stroke($aImg,$aScale) { + $factory = new RectPatternFactory(); + $prect = $factory->Create($this->iPattern,$this->iPatternColor); + $prect->SetDensity($this->iPatternDensity); + + // If height factor is specified as a float between 0,1 then we take it as meaning + // percetage of the scale width between horizontal line. + // If it is an integer > 1 we take it to mean the absolute height in pixels + if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) + $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; + elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 ) + $vs = $this->iHeightFactor; + else { + JpGraphError::RaiseL(6028,$this->iHeightFactor); + // ("Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); + } + + // Clip date to min max dates to show + $st = $aScale->NormalizeDate($this->iStart); + $en = $aScale->NormalizeDate($this->iEnd); + + $limst = max($st,$aScale->iStartDate); + $limen = min($en,$aScale->iEndDate); + + $xt = round($aScale->TranslateDate($limst)); + $xb = round($aScale->TranslateDate($limen)); + $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2)); + $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2)); + $middle = round($yt+($yb-$yt)/2); + $this->StrokeActInfo($aImg,$aScale,$middle); + + // CSIM for title + if( ! empty($this->title->csimtarget) ) { + $colwidth = $this->title->GetColWidth($aImg); + $colstarts=array(); + $aScale->actinfo->GetColStart($aImg,$colstarts,true); + $n = min(count($colwidth),count($this->title->csimtarget)); + for( $i=0; $i < $n; ++$i ) { + $title_xt = $colstarts[$i]; + $title_xb = $title_xt + $colwidth[$i]; + $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; + + if( ! empty($this->title->csimtarget[$i]) ) { + $this->csimarea .= "title->csimtarget[$i]."\""; + + if( ! empty($this->title->csimwintarget[$i]) ) { + $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\" "; + } + + if( ! empty($this->title->csimalt[$i]) ) { + $tmp = $this->title->csimalt[$i]; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + } + } + + // Check if the bar is totally outside the current scale range + if( $en < $aScale->iStartDate || $st > $aScale->iEndDate ) + return; + + + // Remember the positions for the bar + $this->SetConstrainPos($xt,$yt,$xb,$yb); + + + + $prect->ShowFrame(false); + $prect->SetBackground($this->iFillColor); + if( $this->iBreakStyle ) { + $aImg->SetColor($this->iFrameColor); + $olds = $aImg->SetLineStyle($this->iBreakLineStyle); + $oldw = $aImg->SetLineWeight($this->iBreakLineWeight); + $aImg->StyleLine($xt,$yt,$xb,$yt); + $aImg->StyleLine($xt,$yb,$xb,$yb); + $aImg->SetLineStyle($olds); + $aImg->SetLineWeight($oldw); + } + else { + if( $this->iShadow ) { + $aImg->SetColor($this->iFrameColor); + $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); + $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); + $prect->Stroke($aImg); + } + else { + $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); + $prect->Stroke($aImg); + $aImg->SetColor($this->iFrameColor); + $aImg->Rectangle($xt,$yt,$xb,$yb); + } + } + // CSIM for bar + if( ! empty($this->csimtarget) ) { + + $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb"; + $this->csimarea .= "csimtarget."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimarea .= " target=\"".$this->csimwintarget."\" "; + } + + if( $this->csimalt != '' ) { + $tmp = $this->csimalt; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + + // Draw progress bar inside activity bar + if( $this->progress->iProgress > 0 ) { + + $xtp = $aScale->TranslateDate($st); + $xbp = $aScale->TranslateDate($en); + $len = ($xbp-$xtp)*$this->progress->iProgress; + + $endpos = $xtp+$len; + if( $endpos > $xt ) { + + // Take away the length of the progress that is not visible (before the start date) + $len -= ($xt-$xtp); + + // Is the the progress bar visible after the start date? + if( $xtp < $xt ) + $xtp = $xt; + + // Make sure that the progess bar doesn't extend over the end date + if( $xtp+$len-1 > $xb ) + $len = $xb - $xtp ; + + $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); + $prog->SetDensity($this->progress->iDensity); + $prog->SetBackground($this->progress->iFillColor); + $barheight = ($yb-$yt+1); + if( $this->iShadow ) + $barheight -= $this->iShadowWidth; + $progressheight = floor($barheight*$this->progress->iHeight); + $marg = ceil(($barheight-$progressheight)/2); + $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg); + $prog->SetPos($pos); + $prog->Stroke($aImg); + } + } + + // We don't plot the end mark if the bar has been capped + if( $limst == $st ) { + $y = $middle; + // We treat the RIGHT and LEFT triangle mark a little bi + // special so that these marks are placed right under the + // bar. + if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) { + $y = $yb ; + } + $this->leftMark->Stroke($aImg,$xt,$y); + } + if( $limen == $en ) { + $y = $middle; + // We treat the RIGHT and LEFT triangle mark a little bi + // special so that these marks are placed right under the + // bar. + if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) { + $y = $yb ; + } + $this->rightMark->Stroke($aImg,$xb,$y); + + $margin = $this->iCaptionMargin; + if( $this->rightMark->show ) + $margin += $this->rightMark->GetWidth(); + $this->caption->Stroke($aImg,$xb+$margin,$middle); + } + } +} + +//=================================================== +// CLASS MileStone +// Responsible for formatting individual milestones +//=================================================== +class MileStone extends GanttPlotObject { + public $mark; + + //--------------- + // CONSTRUCTOR + function __construct($aVPos,$aLabel,$aDate,$aCaption="") { + GanttPlotObject::__construct(); + $this->caption->Set($aCaption); + $this->caption->Align("left","center"); + $this->caption->SetFont(FF_FONT1,FS_BOLD); + $this->title->Set($aLabel); + $this->title->SetColor("darkred"); + $this->mark = new PlotMark(); + $this->mark->SetWidth(10); + $this->mark->SetType(MARK_DIAMOND); + $this->mark->SetColor("darkred"); + $this->mark->SetFillColor("darkred"); + $this->iVPos = $aVPos; + $this->iStart = $aDate; + } + + //--------------- + // PUBLIC METHODS + + function GetAbsHeight($aImg) { + return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); + } + + function Stroke($aImg,$aScale) { + // Put the mark in the middle at the middle of the day + $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2; + $x = $aScale->TranslateDate($d); + $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); + + $this->StrokeActInfo($aImg,$aScale,$y); + + // CSIM for title + if( ! empty($this->title->csimtarget) ) { + + $yt = round($y - $this->title->GetHeight($aImg)/2); + $yb = round($y + $this->title->GetHeight($aImg)/2); + + $colwidth = $this->title->GetColWidth($aImg); + $colstarts=array(); + $aScale->actinfo->GetColStart($aImg,$colstarts,true); + $n = min(count($colwidth),count($this->title->csimtarget)); + for( $i=0; $i < $n; ++$i ) { + $title_xt = $colstarts[$i]; + $title_xb = $title_xt + $colwidth[$i]; + $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; + + if( !empty($this->title->csimtarget[$i]) ) { + + $this->csimarea .= "title->csimtarget[$i]."\""; + + if( !empty($this->title->csimwintarget[$i]) ) { + $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\""; + } + + if( ! empty($this->title->csimalt[$i]) ) { + $tmp = $this->title->csimalt[$i]; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + } + } + + if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) + return; + + // Remember the coordinates for any constrains linking to + // this milestone + $w = $this->mark->GetWidth()/2; + $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w)); + + // Setup CSIM + if( $this->csimtarget != '' ) { + $this->mark->SetCSIMTarget( $this->csimtarget ); + $this->mark->SetCSIMAlt( $this->csimalt ); + } + + $this->mark->Stroke($aImg,$x,$y); + $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); + + $this->csimarea .= $this->mark->GetCSIMAreas(); + } +} + + +//=================================================== +// CLASS GanttVLine +// Responsible for formatting individual milestones +//=================================================== + +class TextPropertyBelow extends TextProperty { + function __construct($aTxt='') { + parent::__construct($aTxt); + } + + function GetColWidth($aImg,$aMargin=0) { + // Since we are not stroking the title in the columns + // but rather under the graph we want this to return 0. + return array(0); + } +} + +class GanttVLine extends GanttPlotObject { + + private $iLine,$title_margin=3, $iDayOffset=0.5; + private $iStartRow = -1, $iEndRow = -1; + + //--------------- + // CONSTRUCTOR + function __construct($aDate,$aTitle="",$aColor="darkred",$aWeight=2,$aStyle="solid") { + GanttPlotObject::__construct(); + $this->iLine = new LineProperty(); + $this->iLine->SetColor($aColor); + $this->iLine->SetWeight($aWeight); + $this->iLine->SetStyle($aStyle); + $this->iStart = $aDate; + $this->title = new TextPropertyBelow(); + $this->title->Set($aTitle); + } + + //--------------- + // PUBLIC METHODS + + // Set start and end rows for the VLine. By default the entire heigh of the + // Gantt chart is used + function SetRowSpan($aStart, $aEnd=-1) { + $this->iStartRow = $aStart; + $this->iEndRow = $aEnd; + } + + function SetDayOffset($aOff=0.5) { + if( $aOff < 0.0 || $aOff > 1.0 ) { + JpGraphError::RaiseL(6029); + //("Offset for vertical line must be in range [0,1]"); + } + $this->iDayOffset = $aOff; + } + + function SetTitleMargin($aMarg) { + $this->title_margin = $aMarg; + } + + function SetWeight($aWeight) { + $this->iLine->SetWeight($aWeight); + } + + function Stroke($aImg,$aScale) { + $d = $aScale->NormalizeDate($this->iStart); + if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) + return; + if($this->iDayOffset != 0.0) + $d += 24*60*60*$this->iDayOffset; + $x = $aScale->TranslateDate($d);//d=1006858800, + + if( $this->iStartRow > -1 ) { + $y1 = $aScale->TranslateVertPos($this->iStartRow,true) ; + } + else { + $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; + } + + if( $this->iEndRow > -1 ) { + $y2 = $aScale->TranslateVertPos($this->iEndRow); + } + else { + $y2 = $aImg->height - $aImg->bottom_margin; + } + + $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); + $this->title->Align("center","top"); + $this->title->Stroke($aImg,$x,$y2+$this->title_margin); + } +} + +//=================================================== +// CLASS LinkArrow +// Handles the drawing of a an arrow +//=================================================== +class LinkArrow { + private $ix,$iy; + private $isizespec = array( + array(2,3),array(3,5),array(3,8),array(6,15),array(8,22)); + private $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2; + private $iColor='black'; + + function __construct($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) { + $this->iDirection = $aDirection; + $this->iType = $aType; + $this->iSize = $aSize; + $this->ix = $x; + $this->iy = $y; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetSize($aSize) { + $this->iSize = $aSize; + } + + function SetType($aType) { + $this->iType = $aType; + } + + function Stroke($aImg) { + list($dx,$dy) = $this->isizespec[$this->iSize]; + $x = $this->ix; + $y = $this->iy; + switch ( $this->iDirection ) { + case ARROW_DOWN: + $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y); + break; + case ARROW_UP: + $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y); + break; + case ARROW_LEFT: + $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y); + break; + case ARROW_RIGHT: + $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y); + break; + default: + JpGraphError::RaiseL(6030); + //('Unknown arrow direction for link.'); + die(); + break; + } + $aImg->SetColor($this->iColor); + switch( $this->iType ) { + case ARROWT_SOLID: + $aImg->FilledPolygon($c); + break; + case ARROWT_OPEN: + $aImg->Polygon($c); + break; + default: + JpGraphError::RaiseL(6031); + //('Unknown arrow type for link.'); + die(); + break; + } + } +} + +//=================================================== +// CLASS GanttLink +// Handles the drawing of a link line between 2 points +//=================================================== + +class GanttLink { + private $ix1,$ix2,$iy1,$iy2; + private $iPathType=2,$iPathExtend=15; + private $iColor='black',$iWeight=1; + private $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID; + + function __construct($x1=0,$y1=0,$x2=0,$y2=0) { + $this->ix1 = $x1; + $this->ix2 = $x2; + $this->iy1 = $y1; + $this->iy2 = $y2; + } + + function SetPos($x1,$y1,$x2,$y2) { + $this->ix1 = $x1; + $this->ix2 = $x2; + $this->iy1 = $y1; + $this->iy2 = $y2; + } + + function SetPath($aPath) { + $this->iPathType = $aPath; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetArrow($aSize,$aType=ARROWT_SOLID) { + $this->iArrowSize = $aSize; + $this->iArrowType = $aType; + } + + function SetWeight($aWeight) { + $this->iWeight = $aWeight; + } + + function Stroke($aImg) { + // The way the path for the arrow is constructed is partly based + // on some heuristics. This is not an exact science but draws the + // path in a way that, for me, makes esthetic sence. For example + // if the start and end activities are very close we make a small + // detour to endter the target horixontally. If there are more + // space between axctivities then no suh detour is made and the + // target is "hit" directly vertical. I have tried to keep this + // simple. no doubt this could become almost infinitive complex + // and have some real AI. Feel free to modify this. + // This will no-doubt be tweaked as times go by. One design aim + // is to avoid having the user choose what types of arrow + // he wants. + + // The arrow is drawn between (x1,y1) to (x2,y2) + $x1 = $this->ix1 ; + $x2 = $this->ix2 ; + $y1 = $this->iy1 ; + $y2 = $this->iy2 ; + + // Depending on if the target is below or above we have to + // handle thi different. + if( $y2 > $y1 ) { + $arrowtype = ARROW_DOWN; + $midy = round(($y2-$y1)/2+$y1); + if( $x2 > $x1 ) { + switch ( $this->iPathType ) { + case 0: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 1: + case 2: + case 3: + $c = array($x1,$y1,$x2,$y1,$x2,$y2); + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type (='.$this->iPathType .') specified for link.'); + exit(1); + break; + } + } + else { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 2: + // Always extend out horizontally a bit from the first point + // If we draw a link back in time (end to start) and the bars + // are very close we also change the path so it comes in from + // the left on the activity + $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, + $x1+$this->iPathExtend,$midy, + $x2,$midy,$x2,$y2); + break; + case 3: + if( $y2-$midy < 6 ) { + $c = array($x1,$y1,$x1,$midy, + $x2-$this->iPathExtend,$midy, + $x2-$this->iPathExtend,$y2, + $x2,$y2); + $arrowtype = ARROW_RIGHT; + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type specified for link.'); + exit(1); + break; + } + } + $arrow = new LinkArrow($x2,$y2,$arrowtype); + } + else { + // Y2 < Y1 + $arrowtype = ARROW_UP; + $midy = round(($y1-$y2)/2+$y2); + if( $x2 > $x1 ) { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 3: + if( $midy-$y2 < 8 ) { + $arrowtype = ARROW_RIGHT; + $c = array($x1,$y1,$x1,$y2,$x2,$y2); + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type specified for link.'); + break; + } + } + else { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 2: + // Always extend out horizontally a bit from the first point + $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, + $x1+$this->iPathExtend,$midy, + $x2,$midy,$x2,$y2); + break; + case 3: + if( $midy-$y2 < 16 ) { + $arrowtype = ARROW_RIGHT; + $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy, + $x2-$this->iPathExtend,$y2, + $x2,$y2); + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); + //('Internal error: Unknown path type specified for link.'); + break; + } + } + $arrow = new LinkArrow($x2,$y2,$arrowtype); + } + $aImg->SetColor($this->iColor); + $aImg->SetLineWeight($this->iWeight); + $aImg->Polygon($c); + $aImg->SetLineWeight(1); + $arrow->SetColor($this->iColor); + $arrow->SetSize($this->iArrowSize); + $arrow->SetType($this->iArrowType); + $arrow->Stroke($aImg); + } +} + +// +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_gb2312.php b/ext/jpgraph-3.0.7/src/jpgraph_gb2312.php index bfaa58a..5429b4b 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_gb2312.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_gb2312.php @@ -1,1552 +1,1552 @@ - 12288, 8482 => 12289, 8483 => 12290, 8484 => 12539, 8485 => 713, - 8486 => 711, 8487 => 168, 8488 => 12291, 8489 => 12293, 8490 => 8213, - 8491 => 65374, 8492 => 8214, 8493 => 8230, 8494 => 8216, 8495 => 8217, - 8496 => 8220, 8497 => 8221, 8498 => 12308, 8499 => 12309, 8500 => 12296, - 8501 => 12297, 8502 => 12298, 8503 => 12299, 8504 => 12300, 8505 => 12301, - 8506 => 12302, 8507 => 12303, 8508 => 12310, 8509 => 12311, 8510 => 12304, - 8511 => 12305, 8512 => 177, 8513 => 215, 8514 => 247, 8515 => 8758, - 8516 => 8743, 8517 => 8744, 8518 => 8721, 8519 => 8719, 8520 => 8746, - 8521 => 8745, 8522 => 8712, 8523 => 8759, 8524 => 8730, 8525 => 8869, - 8526 => 8741, 8527 => 8736, 8528 => 8978, 8529 => 8857, 8530 => 8747, - 8531 => 8750, 8532 => 8801, 8533 => 8780, 8534 => 8776, 8535 => 8765, - 8536 => 8733, 8537 => 8800, 8538 => 8814, 8539 => 8815, 8540 => 8804, - 8541 => 8805, 8542 => 8734, 8543 => 8757, 8544 => 8756, 8545 => 9794, - 8546 => 9792, 8547 => 176, 8548 => 8242, 8549 => 8243, 8550 => 8451, - 8551 => 65284, 8552 => 164, 8553 => 65504, 8554 => 65505, 8555 => 8240, - 8556 => 167, 8557 => 8470, 8558 => 9734, 8559 => 9733, 8560 => 9675, - 8561 => 9679, 8562 => 9678, 8563 => 9671, 8564 => 9670, 8565 => 9633, - 8566 => 9632, 8567 => 9651, 8568 => 9650, 8569 => 8251, 8570 => 8594, - 8571 => 8592, 8572 => 8593, 8573 => 8595, 8574 => 12307, 8753 => 9352, - 8754 => 9353, 8755 => 9354, 8756 => 9355, 8757 => 9356, 8758 => 9357, - 8759 => 9358, 8760 => 9359, 8761 => 9360, 8762 => 9361, 8763 => 9362, - 8764 => 9363, 8765 => 9364, 8766 => 9365, 8767 => 9366, 8768 => 9367, - 8769 => 9368, 8770 => 9369, 8771 => 9370, 8772 => 9371, 8773 => 9332, - 8774 => 9333, 8775 => 9334, 8776 => 9335, 8777 => 9336, 8778 => 9337, - 8779 => 9338, 8780 => 9339, 8781 => 9340, 8782 => 9341, 8783 => 9342, - 8784 => 9343, 8785 => 9344, 8786 => 9345, 8787 => 9346, 8788 => 9347, - 8789 => 9348, 8790 => 9349, 8791 => 9350, 8792 => 9351, 8793 => 9312, - 8794 => 9313, 8795 => 9314, 8796 => 9315, 8797 => 9316, 8798 => 9317, - 8799 => 9318, 8800 => 9319, 8801 => 9320, 8802 => 9321, 8805 => 12832, - 8806 => 12833, 8807 => 12834, 8808 => 12835, 8809 => 12836, 8810 => 12837, - 8811 => 12838, 8812 => 12839, 8813 => 12840, 8814 => 12841, 8817 => 8544, - 8818 => 8545, 8819 => 8546, 8820 => 8547, 8821 => 8548, 8822 => 8549, - 8823 => 8550, 8824 => 8551, 8825 => 8552, 8826 => 8553, 8827 => 8554, - 8828 => 8555, 8993 => 65281, 8994 => 65282, 8995 => 65283, 8996 => 65509, - 8997 => 65285, 8998 => 65286, 8999 => 65287, 9000 => 65288, 9001 => 65289, - 9002 => 65290, 9003 => 65291, 9004 => 65292, 9005 => 65293, 9006 => 65294, - 9007 => 65295, 9008 => 65296, 9009 => 65297, 9010 => 65298, 9011 => 65299, - 9012 => 65300, 9013 => 65301, 9014 => 65302, 9015 => 65303, 9016 => 65304, - 9017 => 65305, 9018 => 65306, 9019 => 65307, 9020 => 65308, 9021 => 65309, - 9022 => 65310, 9023 => 65311, 9024 => 65312, 9025 => 65313, 9026 => 65314, - 9027 => 65315, 9028 => 65316, 9029 => 65317, 9030 => 65318, 9031 => 65319, - 9032 => 65320, 9033 => 65321, 9034 => 65322, 9035 => 65323, 9036 => 65324, - 9037 => 65325, 9038 => 65326, 9039 => 65327, 9040 => 65328, 9041 => 65329, - 9042 => 65330, 9043 => 65331, 9044 => 65332, 9045 => 65333, 9046 => 65334, - 9047 => 65335, 9048 => 65336, 9049 => 65337, 9050 => 65338, 9051 => 65339, - 9052 => 65340, 9053 => 65341, 9054 => 65342, 9055 => 65343, 9056 => 65344, - 9057 => 65345, 9058 => 65346, 9059 => 65347, 9060 => 65348, 9061 => 65349, - 9062 => 65350, 9063 => 65351, 9064 => 65352, 9065 => 65353, 9066 => 65354, - 9067 => 65355, 9068 => 65356, 9069 => 65357, 9070 => 65358, 9071 => 65359, - 9072 => 65360, 9073 => 65361, 9074 => 65362, 9075 => 65363, 9076 => 65364, - 9077 => 65365, 9078 => 65366, 9079 => 65367, 9080 => 65368, 9081 => 65369, - 9082 => 65370, 9083 => 65371, 9084 => 65372, 9085 => 65373, 9086 => 65507, - 9249 => 12353, 9250 => 12354, 9251 => 12355, 9252 => 12356, 9253 => 12357, - 9254 => 12358, 9255 => 12359, 9256 => 12360, 9257 => 12361, 9258 => 12362, - 9259 => 12363, 9260 => 12364, 9261 => 12365, 9262 => 12366, 9263 => 12367, - 9264 => 12368, 9265 => 12369, 9266 => 12370, 9267 => 12371, 9268 => 12372, - 9269 => 12373, 9270 => 12374, 9271 => 12375, 9272 => 12376, 9273 => 12377, - 9274 => 12378, 9275 => 12379, 9276 => 12380, 9277 => 12381, 9278 => 12382, - 9279 => 12383, 9280 => 12384, 9281 => 12385, 9282 => 12386, 9283 => 12387, - 9284 => 12388, 9285 => 12389, 9286 => 12390, 9287 => 12391, 9288 => 12392, - 9289 => 12393, 9290 => 12394, 9291 => 12395, 9292 => 12396, 9293 => 12397, - 9294 => 12398, 9295 => 12399, 9296 => 12400, 9297 => 12401, 9298 => 12402, - 9299 => 12403, 9300 => 12404, 9301 => 12405, 9302 => 12406, 9303 => 12407, - 9304 => 12408, 9305 => 12409, 9306 => 12410, 9307 => 12411, 9308 => 12412, - 9309 => 12413, 9310 => 12414, 9311 => 12415, 9312 => 12416, 9313 => 12417, - 9314 => 12418, 9315 => 12419, 9316 => 12420, 9317 => 12421, 9318 => 12422, - 9319 => 12423, 9320 => 12424, 9321 => 12425, 9322 => 12426, 9323 => 12427, - 9324 => 12428, 9325 => 12429, 9326 => 12430, 9327 => 12431, 9328 => 12432, - 9329 => 12433, 9330 => 12434, 9331 => 12435, 9505 => 12449, 9506 => 12450, - 9507 => 12451, 9508 => 12452, 9509 => 12453, 9510 => 12454, 9511 => 12455, - 9512 => 12456, 9513 => 12457, 9514 => 12458, 9515 => 12459, 9516 => 12460, - 9517 => 12461, 9518 => 12462, 9519 => 12463, 9520 => 12464, 9521 => 12465, - 9522 => 12466, 9523 => 12467, 9524 => 12468, 9525 => 12469, 9526 => 12470, - 9527 => 12471, 9528 => 12472, 9529 => 12473, 9530 => 12474, 9531 => 12475, - 9532 => 12476, 9533 => 12477, 9534 => 12478, 9535 => 12479, 9536 => 12480, - 9537 => 12481, 9538 => 12482, 9539 => 12483, 9540 => 12484, 9541 => 12485, - 9542 => 12486, 9543 => 12487, 9544 => 12488, 9545 => 12489, 9546 => 12490, - 9547 => 12491, 9548 => 12492, 9549 => 12493, 9550 => 12494, 9551 => 12495, - 9552 => 12496, 9553 => 12497, 9554 => 12498, 9555 => 12499, 9556 => 12500, - 9557 => 12501, 9558 => 12502, 9559 => 12503, 9560 => 12504, 9561 => 12505, - 9562 => 12506, 9563 => 12507, 9564 => 12508, 9565 => 12509, 9566 => 12510, - 9567 => 12511, 9568 => 12512, 9569 => 12513, 9570 => 12514, 9571 => 12515, - 9572 => 12516, 9573 => 12517, 9574 => 12518, 9575 => 12519, 9576 => 12520, - 9577 => 12521, 9578 => 12522, 9579 => 12523, 9580 => 12524, 9581 => 12525, - 9582 => 12526, 9583 => 12527, 9584 => 12528, 9585 => 12529, 9586 => 12530, - 9587 => 12531, 9588 => 12532, 9589 => 12533, 9590 => 12534, 9761 => 913, - 9762 => 914, 9763 => 915, 9764 => 916, 9765 => 917, 9766 => 918, - 9767 => 919, 9768 => 920, 9769 => 921, 9770 => 922, 9771 => 923, - 9772 => 924, 9773 => 925, 9774 => 926, 9775 => 927, 9776 => 928, - 9777 => 929, 9778 => 931, 9779 => 932, 9780 => 933, 9781 => 934, - 9782 => 935, 9783 => 936, 9784 => 937, 9793 => 945, 9794 => 946, - 9795 => 947, 9796 => 948, 9797 => 949, 9798 => 950, 9799 => 951, - 9800 => 952, 9801 => 953, 9802 => 954, 9803 => 955, 9804 => 956, - 9805 => 957, 9806 => 958, 9807 => 959, 9808 => 960, 9809 => 961, - 9810 => 963, 9811 => 964, 9812 => 965, 9813 => 966, 9814 => 967, - 9815 => 968, 9816 => 969, 10017 => 1040, 10018 => 1041, 10019 => 1042, - 10020 => 1043, 10021 => 1044, 10022 => 1045, 10023 => 1025, 10024 => 1046, - 10025 => 1047, 10026 => 1048, 10027 => 1049, 10028 => 1050, 10029 => 1051, - 10030 => 1052, 10031 => 1053, 10032 => 1054, 10033 => 1055, 10034 => 1056, - 10035 => 1057, 10036 => 1058, 10037 => 1059, 10038 => 1060, 10039 => 1061, - 10040 => 1062, 10041 => 1063, 10042 => 1064, 10043 => 1065, 10044 => 1066, - 10045 => 1067, 10046 => 1068, 10047 => 1069, 10048 => 1070, 10049 => 1071, - 10065 => 1072, 10066 => 1073, 10067 => 1074, 10068 => 1075, 10069 => 1076, - 10070 => 1077, 10071 => 1105, 10072 => 1078, 10073 => 1079, 10074 => 1080, - 10075 => 1081, 10076 => 1082, 10077 => 1083, 10078 => 1084, 10079 => 1085, - 10080 => 1086, 10081 => 1087, 10082 => 1088, 10083 => 1089, 10084 => 1090, - 10085 => 1091, 10086 => 1092, 10087 => 1093, 10088 => 1094, 10089 => 1095, - 10090 => 1096, 10091 => 1097, 10092 => 1098, 10093 => 1099, 10094 => 1100, - 10095 => 1101, 10096 => 1102, 10097 => 1103, 10273 => 257, 10274 => 225, - 10275 => 462, 10276 => 224, 10277 => 275, 10278 => 233, 10279 => 283, - 10280 => 232, 10281 => 299, 10282 => 237, 10283 => 464, 10284 => 236, - 10285 => 333, 10286 => 243, 10287 => 466, 10288 => 242, 10289 => 363, - 10290 => 250, 10291 => 468, 10292 => 249, 10293 => 470, 10294 => 472, - 10295 => 474, 10296 => 476, 10297 => 252, 10298 => 234, 10309 => 12549, - 10310 => 12550, 10311 => 12551, 10312 => 12552, 10313 => 12553, 10314 => 12554, - 10315 => 12555, 10316 => 12556, 10317 => 12557, 10318 => 12558, 10319 => 12559, - 10320 => 12560, 10321 => 12561, 10322 => 12562, 10323 => 12563, 10324 => 12564, - 10325 => 12565, 10326 => 12566, 10327 => 12567, 10328 => 12568, 10329 => 12569, - 10330 => 12570, 10331 => 12571, 10332 => 12572, 10333 => 12573, 10334 => 12574, - 10335 => 12575, 10336 => 12576, 10337 => 12577, 10338 => 12578, 10339 => 12579, - 10340 => 12580, 10341 => 12581, 10342 => 12582, 10343 => 12583, 10344 => 12584, - 10345 => 12585, 10532 => 9472, 10533 => 9473, 10534 => 9474, 10535 => 9475, - 10536 => 9476, 10537 => 9477, 10538 => 9478, 10539 => 9479, 10540 => 9480, - 10541 => 9481, 10542 => 9482, 10543 => 9483, 10544 => 9484, 10545 => 9485, - 10546 => 9486, 10547 => 9487, 10548 => 9488, 10549 => 9489, 10550 => 9490, - 10551 => 9491, 10552 => 9492, 10553 => 9493, 10554 => 9494, 10555 => 9495, - 10556 => 9496, 10557 => 9497, 10558 => 9498, 10559 => 9499, 10560 => 9500, - 10561 => 9501, 10562 => 9502, 10563 => 9503, 10564 => 9504, 10565 => 9505, - 10566 => 9506, 10567 => 9507, 10568 => 9508, 10569 => 9509, 10570 => 9510, - 10571 => 9511, 10572 => 9512, 10573 => 9513, 10574 => 9514, 10575 => 9515, - 10576 => 9516, 10577 => 9517, 10578 => 9518, 10579 => 9519, 10580 => 9520, - 10581 => 9521, 10582 => 9522, 10583 => 9523, 10584 => 9524, 10585 => 9525, - 10586 => 9526, 10587 => 9527, 10588 => 9528, 10589 => 9529, 10590 => 9530, - 10591 => 9531, 10592 => 9532, 10593 => 9533, 10594 => 9534, 10595 => 9535, - 10596 => 9536, 10597 => 9537, 10598 => 9538, 10599 => 9539, 10600 => 9540, - 10601 => 9541, 10602 => 9542, 10603 => 9543, 10604 => 9544, 10605 => 9545, - 10606 => 9546, 10607 => 9547, 12321 => 21834, 12322 => 38463, 12323 => 22467, - 12324 => 25384, 12325 => 21710, 12326 => 21769, 12327 => 21696, 12328 => 30353, - 12329 => 30284, 12330 => 34108, 12331 => 30702, 12332 => 33406, 12333 => 30861, - 12334 => 29233, 12335 => 38552, 12336 => 38797, 12337 => 27688, 12338 => 23433, - 12339 => 20474, 12340 => 25353, 12341 => 26263, 12342 => 23736, 12343 => 33018, - 12344 => 26696, 12345 => 32942, 12346 => 26114, 12347 => 30414, 12348 => 20985, - 12349 => 25942, 12350 => 29100, 12351 => 32753, 12352 => 34948, 12353 => 20658, - 12354 => 22885, 12355 => 25034, 12356 => 28595, 12357 => 33453, 12358 => 25420, - 12359 => 25170, 12360 => 21485, 12361 => 21543, 12362 => 31494, 12363 => 20843, - 12364 => 30116, 12365 => 24052, 12366 => 25300, 12367 => 36299, 12368 => 38774, - 12369 => 25226, 12370 => 32793, 12371 => 22365, 12372 => 38712, 12373 => 32610, - 12374 => 29240, 12375 => 30333, 12376 => 26575, 12377 => 30334, 12378 => 25670, - 12379 => 20336, 12380 => 36133, 12381 => 25308, 12382 => 31255, 12383 => 26001, - 12384 => 29677, 12385 => 25644, 12386 => 25203, 12387 => 33324, 12388 => 39041, - 12389 => 26495, 12390 => 29256, 12391 => 25198, 12392 => 25292, 12393 => 20276, - 12394 => 29923, 12395 => 21322, 12396 => 21150, 12397 => 32458, 12398 => 37030, - 12399 => 24110, 12400 => 26758, 12401 => 27036, 12402 => 33152, 12403 => 32465, - 12404 => 26834, 12405 => 30917, 12406 => 34444, 12407 => 38225, 12408 => 20621, - 12409 => 35876, 12410 => 33502, 12411 => 32990, 12412 => 21253, 12413 => 35090, - 12414 => 21093, 12577 => 34180, 12578 => 38649, 12579 => 20445, 12580 => 22561, - 12581 => 39281, 12582 => 23453, 12583 => 25265, 12584 => 25253, 12585 => 26292, - 12586 => 35961, 12587 => 40077, 12588 => 29190, 12589 => 26479, 12590 => 30865, - 12591 => 24754, 12592 => 21329, 12593 => 21271, 12594 => 36744, 12595 => 32972, - 12596 => 36125, 12597 => 38049, 12598 => 20493, 12599 => 29384, 12600 => 22791, - 12601 => 24811, 12602 => 28953, 12603 => 34987, 12604 => 22868, 12605 => 33519, - 12606 => 26412, 12607 => 31528, 12608 => 23849, 12609 => 32503, 12610 => 29997, - 12611 => 27893, 12612 => 36454, 12613 => 36856, 12614 => 36924, 12615 => 40763, - 12616 => 27604, 12617 => 37145, 12618 => 31508, 12619 => 24444, 12620 => 30887, - 12621 => 34006, 12622 => 34109, 12623 => 27605, 12624 => 27609, 12625 => 27606, - 12626 => 24065, 12627 => 24199, 12628 => 30201, 12629 => 38381, 12630 => 25949, - 12631 => 24330, 12632 => 24517, 12633 => 36767, 12634 => 22721, 12635 => 33218, - 12636 => 36991, 12637 => 38491, 12638 => 38829, 12639 => 36793, 12640 => 32534, - 12641 => 36140, 12642 => 25153, 12643 => 20415, 12644 => 21464, 12645 => 21342, - 12646 => 36776, 12647 => 36777, 12648 => 36779, 12649 => 36941, 12650 => 26631, - 12651 => 24426, 12652 => 33176, 12653 => 34920, 12654 => 40150, 12655 => 24971, - 12656 => 21035, 12657 => 30250, 12658 => 24428, 12659 => 25996, 12660 => 28626, - 12661 => 28392, 12662 => 23486, 12663 => 25672, 12664 => 20853, 12665 => 20912, - 12666 => 26564, 12667 => 19993, 12668 => 31177, 12669 => 39292, 12670 => 28851, - 12833 => 30149, 12834 => 24182, 12835 => 29627, 12836 => 33760, 12837 => 25773, - 12838 => 25320, 12839 => 38069, 12840 => 27874, 12841 => 21338, 12842 => 21187, - 12843 => 25615, 12844 => 38082, 12845 => 31636, 12846 => 20271, 12847 => 24091, - 12848 => 33334, 12849 => 33046, 12850 => 33162, 12851 => 28196, 12852 => 27850, - 12853 => 39539, 12854 => 25429, 12855 => 21340, 12856 => 21754, 12857 => 34917, - 12858 => 22496, 12859 => 19981, 12860 => 24067, 12861 => 27493, 12862 => 31807, - 12863 => 37096, 12864 => 24598, 12865 => 25830, 12866 => 29468, 12867 => 35009, - 12868 => 26448, 12869 => 25165, 12870 => 36130, 12871 => 30572, 12872 => 36393, - 12873 => 37319, 12874 => 24425, 12875 => 33756, 12876 => 34081, 12877 => 39184, - 12878 => 21442, 12879 => 34453, 12880 => 27531, 12881 => 24813, 12882 => 24808, - 12883 => 28799, 12884 => 33485, 12885 => 33329, 12886 => 20179, 12887 => 27815, - 12888 => 34255, 12889 => 25805, 12890 => 31961, 12891 => 27133, 12892 => 26361, - 12893 => 33609, 12894 => 21397, 12895 => 31574, 12896 => 20391, 12897 => 20876, - 12898 => 27979, 12899 => 23618, 12900 => 36461, 12901 => 25554, 12902 => 21449, - 12903 => 33580, 12904 => 33590, 12905 => 26597, 12906 => 30900, 12907 => 25661, - 12908 => 23519, 12909 => 23700, 12910 => 24046, 12911 => 35815, 12912 => 25286, - 12913 => 26612, 12914 => 35962, 12915 => 25600, 12916 => 25530, 12917 => 34633, - 12918 => 39307, 12919 => 35863, 12920 => 32544, 12921 => 38130, 12922 => 20135, - 12923 => 38416, 12924 => 39076, 12925 => 26124, 12926 => 29462, 13089 => 22330, - 13090 => 23581, 13091 => 24120, 13092 => 38271, 13093 => 20607, 13094 => 32928, - 13095 => 21378, 13096 => 25950, 13097 => 30021, 13098 => 21809, 13099 => 20513, - 13100 => 36229, 13101 => 25220, 13102 => 38046, 13103 => 26397, 13104 => 22066, - 13105 => 28526, 13106 => 24034, 13107 => 21557, 13108 => 28818, 13109 => 36710, - 13110 => 25199, 13111 => 25764, 13112 => 25507, 13113 => 24443, 13114 => 28552, - 13115 => 37108, 13116 => 33251, 13117 => 36784, 13118 => 23576, 13119 => 26216, - 13120 => 24561, 13121 => 27785, 13122 => 38472, 13123 => 36225, 13124 => 34924, - 13125 => 25745, 13126 => 31216, 13127 => 22478, 13128 => 27225, 13129 => 25104, - 13130 => 21576, 13131 => 20056, 13132 => 31243, 13133 => 24809, 13134 => 28548, - 13135 => 35802, 13136 => 25215, 13137 => 36894, 13138 => 39563, 13139 => 31204, - 13140 => 21507, 13141 => 30196, 13142 => 25345, 13143 => 21273, 13144 => 27744, - 13145 => 36831, 13146 => 24347, 13147 => 39536, 13148 => 32827, 13149 => 40831, - 13150 => 20360, 13151 => 23610, 13152 => 36196, 13153 => 32709, 13154 => 26021, - 13155 => 28861, 13156 => 20805, 13157 => 20914, 13158 => 34411, 13159 => 23815, - 13160 => 23456, 13161 => 25277, 13162 => 37228, 13163 => 30068, 13164 => 36364, - 13165 => 31264, 13166 => 24833, 13167 => 31609, 13168 => 20167, 13169 => 32504, - 13170 => 30597, 13171 => 19985, 13172 => 33261, 13173 => 21021, 13174 => 20986, - 13175 => 27249, 13176 => 21416, 13177 => 36487, 13178 => 38148, 13179 => 38607, - 13180 => 28353, 13181 => 38500, 13182 => 26970, 13345 => 30784, 13346 => 20648, - 13347 => 30679, 13348 => 25616, 13349 => 35302, 13350 => 22788, 13351 => 25571, - 13352 => 24029, 13353 => 31359, 13354 => 26941, 13355 => 20256, 13356 => 33337, - 13357 => 21912, 13358 => 20018, 13359 => 30126, 13360 => 31383, 13361 => 24162, - 13362 => 24202, 13363 => 38383, 13364 => 21019, 13365 => 21561, 13366 => 28810, - 13367 => 25462, 13368 => 38180, 13369 => 22402, 13370 => 26149, 13371 => 26943, - 13372 => 37255, 13373 => 21767, 13374 => 28147, 13375 => 32431, 13376 => 34850, - 13377 => 25139, 13378 => 32496, 13379 => 30133, 13380 => 33576, 13381 => 30913, - 13382 => 38604, 13383 => 36766, 13384 => 24904, 13385 => 29943, 13386 => 35789, - 13387 => 27492, 13388 => 21050, 13389 => 36176, 13390 => 27425, 13391 => 32874, - 13392 => 33905, 13393 => 22257, 13394 => 21254, 13395 => 20174, 13396 => 19995, - 13397 => 20945, 13398 => 31895, 13399 => 37259, 13400 => 31751, 13401 => 20419, - 13402 => 36479, 13403 => 31713, 13404 => 31388, 13405 => 25703, 13406 => 23828, - 13407 => 20652, 13408 => 33030, 13409 => 30209, 13410 => 31929, 13411 => 28140, - 13412 => 32736, 13413 => 26449, 13414 => 23384, 13415 => 23544, 13416 => 30923, - 13417 => 25774, 13418 => 25619, 13419 => 25514, 13420 => 25387, 13421 => 38169, - 13422 => 25645, 13423 => 36798, 13424 => 31572, 13425 => 30249, 13426 => 25171, - 13427 => 22823, 13428 => 21574, 13429 => 27513, 13430 => 20643, 13431 => 25140, - 13432 => 24102, 13433 => 27526, 13434 => 20195, 13435 => 36151, 13436 => 34955, - 13437 => 24453, 13438 => 36910, 13601 => 24608, 13602 => 32829, 13603 => 25285, - 13604 => 20025, 13605 => 21333, 13606 => 37112, 13607 => 25528, 13608 => 32966, - 13609 => 26086, 13610 => 27694, 13611 => 20294, 13612 => 24814, 13613 => 28129, - 13614 => 35806, 13615 => 24377, 13616 => 34507, 13617 => 24403, 13618 => 25377, - 13619 => 20826, 13620 => 33633, 13621 => 26723, 13622 => 20992, 13623 => 25443, - 13624 => 36424, 13625 => 20498, 13626 => 23707, 13627 => 31095, 13628 => 23548, - 13629 => 21040, 13630 => 31291, 13631 => 24764, 13632 => 36947, 13633 => 30423, - 13634 => 24503, 13635 => 24471, 13636 => 30340, 13637 => 36460, 13638 => 28783, - 13639 => 30331, 13640 => 31561, 13641 => 30634, 13642 => 20979, 13643 => 37011, - 13644 => 22564, 13645 => 20302, 13646 => 28404, 13647 => 36842, 13648 => 25932, - 13649 => 31515, 13650 => 29380, 13651 => 28068, 13652 => 32735, 13653 => 23265, - 13654 => 25269, 13655 => 24213, 13656 => 22320, 13657 => 33922, 13658 => 31532, - 13659 => 24093, 13660 => 24351, 13661 => 36882, 13662 => 32532, 13663 => 39072, - 13664 => 25474, 13665 => 28359, 13666 => 30872, 13667 => 28857, 13668 => 20856, - 13669 => 38747, 13670 => 22443, 13671 => 30005, 13672 => 20291, 13673 => 30008, - 13674 => 24215, 13675 => 24806, 13676 => 22880, 13677 => 28096, 13678 => 27583, - 13679 => 30857, 13680 => 21500, 13681 => 38613, 13682 => 20939, 13683 => 20993, - 13684 => 25481, 13685 => 21514, 13686 => 38035, 13687 => 35843, 13688 => 36300, - 13689 => 29241, 13690 => 30879, 13691 => 34678, 13692 => 36845, 13693 => 35853, - 13694 => 21472, 13857 => 19969, 13858 => 30447, 13859 => 21486, 13860 => 38025, - 13861 => 39030, 13862 => 40718, 13863 => 38189, 13864 => 23450, 13865 => 35746, - 13866 => 20002, 13867 => 19996, 13868 => 20908, 13869 => 33891, 13870 => 25026, - 13871 => 21160, 13872 => 26635, 13873 => 20375, 13874 => 24683, 13875 => 20923, - 13876 => 27934, 13877 => 20828, 13878 => 25238, 13879 => 26007, 13880 => 38497, - 13881 => 35910, 13882 => 36887, 13883 => 30168, 13884 => 37117, 13885 => 30563, - 13886 => 27602, 13887 => 29322, 13888 => 29420, 13889 => 35835, 13890 => 22581, - 13891 => 30585, 13892 => 36172, 13893 => 26460, 13894 => 38208, 13895 => 32922, - 13896 => 24230, 13897 => 28193, 13898 => 22930, 13899 => 31471, 13900 => 30701, - 13901 => 38203, 13902 => 27573, 13903 => 26029, 13904 => 32526, 13905 => 22534, - 13906 => 20817, 13907 => 38431, 13908 => 23545, 13909 => 22697, 13910 => 21544, - 13911 => 36466, 13912 => 25958, 13913 => 39039, 13914 => 22244, 13915 => 38045, - 13916 => 30462, 13917 => 36929, 13918 => 25479, 13919 => 21702, 13920 => 22810, - 13921 => 22842, 13922 => 22427, 13923 => 36530, 13924 => 26421, 13925 => 36346, - 13926 => 33333, 13927 => 21057, 13928 => 24816, 13929 => 22549, 13930 => 34558, - 13931 => 23784, 13932 => 40517, 13933 => 20420, 13934 => 39069, 13935 => 35769, - 13936 => 23077, 13937 => 24694, 13938 => 21380, 13939 => 25212, 13940 => 36943, - 13941 => 37122, 13942 => 39295, 13943 => 24681, 13944 => 32780, 13945 => 20799, - 13946 => 32819, 13947 => 23572, 13948 => 39285, 13949 => 27953, 13950 => 20108, - 14113 => 36144, 14114 => 21457, 14115 => 32602, 14116 => 31567, 14117 => 20240, - 14118 => 20047, 14119 => 38400, 14120 => 27861, 14121 => 29648, 14122 => 34281, - 14123 => 24070, 14124 => 30058, 14125 => 32763, 14126 => 27146, 14127 => 30718, - 14128 => 38034, 14129 => 32321, 14130 => 20961, 14131 => 28902, 14132 => 21453, - 14133 => 36820, 14134 => 33539, 14135 => 36137, 14136 => 29359, 14137 => 39277, - 14138 => 27867, 14139 => 22346, 14140 => 33459, 14141 => 26041, 14142 => 32938, - 14143 => 25151, 14144 => 38450, 14145 => 22952, 14146 => 20223, 14147 => 35775, - 14148 => 32442, 14149 => 25918, 14150 => 33778, 14151 => 38750, 14152 => 21857, - 14153 => 39134, 14154 => 32933, 14155 => 21290, 14156 => 35837, 14157 => 21536, - 14158 => 32954, 14159 => 24223, 14160 => 27832, 14161 => 36153, 14162 => 33452, - 14163 => 37210, 14164 => 21545, 14165 => 27675, 14166 => 20998, 14167 => 32439, - 14168 => 22367, 14169 => 28954, 14170 => 27774, 14171 => 31881, 14172 => 22859, - 14173 => 20221, 14174 => 24575, 14175 => 24868, 14176 => 31914, 14177 => 20016, - 14178 => 23553, 14179 => 26539, 14180 => 34562, 14181 => 23792, 14182 => 38155, - 14183 => 39118, 14184 => 30127, 14185 => 28925, 14186 => 36898, 14187 => 20911, - 14188 => 32541, 14189 => 35773, 14190 => 22857, 14191 => 20964, 14192 => 20315, - 14193 => 21542, 14194 => 22827, 14195 => 25975, 14196 => 32932, 14197 => 23413, - 14198 => 25206, 14199 => 25282, 14200 => 36752, 14201 => 24133, 14202 => 27679, - 14203 => 31526, 14204 => 20239, 14205 => 20440, 14206 => 26381, 14369 => 28014, - 14370 => 28074, 14371 => 31119, 14372 => 34993, 14373 => 24343, 14374 => 29995, - 14375 => 25242, 14376 => 36741, 14377 => 20463, 14378 => 37340, 14379 => 26023, - 14380 => 33071, 14381 => 33105, 14382 => 24220, 14383 => 33104, 14384 => 36212, - 14385 => 21103, 14386 => 35206, 14387 => 36171, 14388 => 22797, 14389 => 20613, - 14390 => 20184, 14391 => 38428, 14392 => 29238, 14393 => 33145, 14394 => 36127, - 14395 => 23500, 14396 => 35747, 14397 => 38468, 14398 => 22919, 14399 => 32538, - 14400 => 21648, 14401 => 22134, 14402 => 22030, 14403 => 35813, 14404 => 25913, - 14405 => 27010, 14406 => 38041, 14407 => 30422, 14408 => 28297, 14409 => 24178, - 14410 => 29976, 14411 => 26438, 14412 => 26577, 14413 => 31487, 14414 => 32925, - 14415 => 36214, 14416 => 24863, 14417 => 31174, 14418 => 25954, 14419 => 36195, - 14420 => 20872, 14421 => 21018, 14422 => 38050, 14423 => 32568, 14424 => 32923, - 14425 => 32434, 14426 => 23703, 14427 => 28207, 14428 => 26464, 14429 => 31705, - 14430 => 30347, 14431 => 39640, 14432 => 33167, 14433 => 32660, 14434 => 31957, - 14435 => 25630, 14436 => 38224, 14437 => 31295, 14438 => 21578, 14439 => 21733, - 14440 => 27468, 14441 => 25601, 14442 => 25096, 14443 => 40509, 14444 => 33011, - 14445 => 30105, 14446 => 21106, 14447 => 38761, 14448 => 33883, 14449 => 26684, - 14450 => 34532, 14451 => 38401, 14452 => 38548, 14453 => 38124, 14454 => 20010, - 14455 => 21508, 14456 => 32473, 14457 => 26681, 14458 => 36319, 14459 => 32789, - 14460 => 26356, 14461 => 24218, 14462 => 32697, 14625 => 22466, 14626 => 32831, - 14627 => 26775, 14628 => 24037, 14629 => 25915, 14630 => 21151, 14631 => 24685, - 14632 => 40858, 14633 => 20379, 14634 => 36524, 14635 => 20844, 14636 => 23467, - 14637 => 24339, 14638 => 24041, 14639 => 27742, 14640 => 25329, 14641 => 36129, - 14642 => 20849, 14643 => 38057, 14644 => 21246, 14645 => 27807, 14646 => 33503, - 14647 => 29399, 14648 => 22434, 14649 => 26500, 14650 => 36141, 14651 => 22815, - 14652 => 36764, 14653 => 33735, 14654 => 21653, 14655 => 31629, 14656 => 20272, - 14657 => 27837, 14658 => 23396, 14659 => 22993, 14660 => 40723, 14661 => 21476, - 14662 => 34506, 14663 => 39592, 14664 => 35895, 14665 => 32929, 14666 => 25925, - 14667 => 39038, 14668 => 22266, 14669 => 38599, 14670 => 21038, 14671 => 29916, - 14672 => 21072, 14673 => 23521, 14674 => 25346, 14675 => 35074, 14676 => 20054, - 14677 => 25296, 14678 => 24618, 14679 => 26874, 14680 => 20851, 14681 => 23448, - 14682 => 20896, 14683 => 35266, 14684 => 31649, 14685 => 39302, 14686 => 32592, - 14687 => 24815, 14688 => 28748, 14689 => 36143, 14690 => 20809, 14691 => 24191, - 14692 => 36891, 14693 => 29808, 14694 => 35268, 14695 => 22317, 14696 => 30789, - 14697 => 24402, 14698 => 40863, 14699 => 38394, 14700 => 36712, 14701 => 39740, - 14702 => 35809, 14703 => 30328, 14704 => 26690, 14705 => 26588, 14706 => 36330, - 14707 => 36149, 14708 => 21053, 14709 => 36746, 14710 => 28378, 14711 => 26829, - 14712 => 38149, 14713 => 37101, 14714 => 22269, 14715 => 26524, 14716 => 35065, - 14717 => 36807, 14718 => 21704, 14881 => 39608, 14882 => 23401, 14883 => 28023, - 14884 => 27686, 14885 => 20133, 14886 => 23475, 14887 => 39559, 14888 => 37219, - 14889 => 25000, 14890 => 37039, 14891 => 38889, 14892 => 21547, 14893 => 28085, - 14894 => 23506, 14895 => 20989, 14896 => 21898, 14897 => 32597, 14898 => 32752, - 14899 => 25788, 14900 => 25421, 14901 => 26097, 14902 => 25022, 14903 => 24717, - 14904 => 28938, 14905 => 27735, 14906 => 27721, 14907 => 22831, 14908 => 26477, - 14909 => 33322, 14910 => 22741, 14911 => 22158, 14912 => 35946, 14913 => 27627, - 14914 => 37085, 14915 => 22909, 14916 => 32791, 14917 => 21495, 14918 => 28009, - 14919 => 21621, 14920 => 21917, 14921 => 33655, 14922 => 33743, 14923 => 26680, - 14924 => 31166, 14925 => 21644, 14926 => 20309, 14927 => 21512, 14928 => 30418, - 14929 => 35977, 14930 => 38402, 14931 => 27827, 14932 => 28088, 14933 => 36203, - 14934 => 35088, 14935 => 40548, 14936 => 36154, 14937 => 22079, 14938 => 40657, - 14939 => 30165, 14940 => 24456, 14941 => 29408, 14942 => 24680, 14943 => 21756, - 14944 => 20136, 14945 => 27178, 14946 => 34913, 14947 => 24658, 14948 => 36720, - 14949 => 21700, 14950 => 28888, 14951 => 34425, 14952 => 40511, 14953 => 27946, - 14954 => 23439, 14955 => 24344, 14956 => 32418, 14957 => 21897, 14958 => 20399, - 14959 => 29492, 14960 => 21564, 14961 => 21402, 14962 => 20505, 14963 => 21518, - 14964 => 21628, 14965 => 20046, 14966 => 24573, 14967 => 29786, 14968 => 22774, - 14969 => 33899, 14970 => 32993, 14971 => 34676, 14972 => 29392, 14973 => 31946, - 14974 => 28246, 15137 => 24359, 15138 => 34382, 15139 => 21804, 15140 => 25252, - 15141 => 20114, 15142 => 27818, 15143 => 25143, 15144 => 33457, 15145 => 21719, - 15146 => 21326, 15147 => 29502, 15148 => 28369, 15149 => 30011, 15150 => 21010, - 15151 => 21270, 15152 => 35805, 15153 => 27088, 15154 => 24458, 15155 => 24576, - 15156 => 28142, 15157 => 22351, 15158 => 27426, 15159 => 29615, 15160 => 26707, - 15161 => 36824, 15162 => 32531, 15163 => 25442, 15164 => 24739, 15165 => 21796, - 15166 => 30186, 15167 => 35938, 15168 => 28949, 15169 => 28067, 15170 => 23462, - 15171 => 24187, 15172 => 33618, 15173 => 24908, 15174 => 40644, 15175 => 30970, - 15176 => 34647, 15177 => 31783, 15178 => 30343, 15179 => 20976, 15180 => 24822, - 15181 => 29004, 15182 => 26179, 15183 => 24140, 15184 => 24653, 15185 => 35854, - 15186 => 28784, 15187 => 25381, 15188 => 36745, 15189 => 24509, 15190 => 24674, - 15191 => 34516, 15192 => 22238, 15193 => 27585, 15194 => 24724, 15195 => 24935, - 15196 => 21321, 15197 => 24800, 15198 => 26214, 15199 => 36159, 15200 => 31229, - 15201 => 20250, 15202 => 28905, 15203 => 27719, 15204 => 35763, 15205 => 35826, - 15206 => 32472, 15207 => 33636, 15208 => 26127, 15209 => 23130, 15210 => 39746, - 15211 => 27985, 15212 => 28151, 15213 => 35905, 15214 => 27963, 15215 => 20249, - 15216 => 28779, 15217 => 33719, 15218 => 25110, 15219 => 24785, 15220 => 38669, - 15221 => 36135, 15222 => 31096, 15223 => 20987, 15224 => 22334, 15225 => 22522, - 15226 => 26426, 15227 => 30072, 15228 => 31293, 15229 => 31215, 15230 => 31637, - 15393 => 32908, 15394 => 39269, 15395 => 36857, 15396 => 28608, 15397 => 35749, - 15398 => 40481, 15399 => 23020, 15400 => 32489, 15401 => 32521, 15402 => 21513, - 15403 => 26497, 15404 => 26840, 15405 => 36753, 15406 => 31821, 15407 => 38598, - 15408 => 21450, 15409 => 24613, 15410 => 30142, 15411 => 27762, 15412 => 21363, - 15413 => 23241, 15414 => 32423, 15415 => 25380, 15416 => 20960, 15417 => 33034, - 15418 => 24049, 15419 => 34015, 15420 => 25216, 15421 => 20864, 15422 => 23395, - 15423 => 20238, 15424 => 31085, 15425 => 21058, 15426 => 24760, 15427 => 27982, - 15428 => 23492, 15429 => 23490, 15430 => 35745, 15431 => 35760, 15432 => 26082, - 15433 => 24524, 15434 => 38469, 15435 => 22931, 15436 => 32487, 15437 => 32426, - 15438 => 22025, 15439 => 26551, 15440 => 22841, 15441 => 20339, 15442 => 23478, - 15443 => 21152, 15444 => 33626, 15445 => 39050, 15446 => 36158, 15447 => 30002, - 15448 => 38078, 15449 => 20551, 15450 => 31292, 15451 => 20215, 15452 => 26550, - 15453 => 39550, 15454 => 23233, 15455 => 27516, 15456 => 30417, 15457 => 22362, - 15458 => 23574, 15459 => 31546, 15460 => 38388, 15461 => 29006, 15462 => 20860, - 15463 => 32937, 15464 => 33392, 15465 => 22904, 15466 => 32516, 15467 => 33575, - 15468 => 26816, 15469 => 26604, 15470 => 30897, 15471 => 30839, 15472 => 25315, - 15473 => 25441, 15474 => 31616, 15475 => 20461, 15476 => 21098, 15477 => 20943, - 15478 => 33616, 15479 => 27099, 15480 => 37492, 15481 => 36341, 15482 => 36145, - 15483 => 35265, 15484 => 38190, 15485 => 31661, 15486 => 20214, 15649 => 20581, - 15650 => 33328, 15651 => 21073, 15652 => 39279, 15653 => 28176, 15654 => 28293, - 15655 => 28071, 15656 => 24314, 15657 => 20725, 15658 => 23004, 15659 => 23558, - 15660 => 27974, 15661 => 27743, 15662 => 30086, 15663 => 33931, 15664 => 26728, - 15665 => 22870, 15666 => 35762, 15667 => 21280, 15668 => 37233, 15669 => 38477, - 15670 => 34121, 15671 => 26898, 15672 => 30977, 15673 => 28966, 15674 => 33014, - 15675 => 20132, 15676 => 37066, 15677 => 27975, 15678 => 39556, 15679 => 23047, - 15680 => 22204, 15681 => 25605, 15682 => 38128, 15683 => 30699, 15684 => 20389, - 15685 => 33050, 15686 => 29409, 15687 => 35282, 15688 => 39290, 15689 => 32564, - 15690 => 32478, 15691 => 21119, 15692 => 25945, 15693 => 37237, 15694 => 36735, - 15695 => 36739, 15696 => 21483, 15697 => 31382, 15698 => 25581, 15699 => 25509, - 15700 => 30342, 15701 => 31224, 15702 => 34903, 15703 => 38454, 15704 => 25130, - 15705 => 21163, 15706 => 33410, 15707 => 26708, 15708 => 26480, 15709 => 25463, - 15710 => 30571, 15711 => 31469, 15712 => 27905, 15713 => 32467, 15714 => 35299, - 15715 => 22992, 15716 => 25106, 15717 => 34249, 15718 => 33445, 15719 => 30028, - 15720 => 20511, 15721 => 20171, 15722 => 30117, 15723 => 35819, 15724 => 23626, - 15725 => 24062, 15726 => 31563, 15727 => 26020, 15728 => 37329, 15729 => 20170, - 15730 => 27941, 15731 => 35167, 15732 => 32039, 15733 => 38182, 15734 => 20165, - 15735 => 35880, 15736 => 36827, 15737 => 38771, 15738 => 26187, 15739 => 31105, - 15740 => 36817, 15741 => 28908, 15742 => 28024, 15905 => 23613, 15906 => 21170, - 15907 => 33606, 15908 => 20834, 15909 => 33550, 15910 => 30555, 15911 => 26230, - 15912 => 40120, 15913 => 20140, 15914 => 24778, 15915 => 31934, 15916 => 31923, - 15917 => 32463, 15918 => 20117, 15919 => 35686, 15920 => 26223, 15921 => 39048, - 15922 => 38745, 15923 => 22659, 15924 => 25964, 15925 => 38236, 15926 => 24452, - 15927 => 30153, 15928 => 38742, 15929 => 31455, 15930 => 31454, 15931 => 20928, - 15932 => 28847, 15933 => 31384, 15934 => 25578, 15935 => 31350, 15936 => 32416, - 15937 => 29590, 15938 => 38893, 15939 => 20037, 15940 => 28792, 15941 => 20061, - 15942 => 37202, 15943 => 21417, 15944 => 25937, 15945 => 26087, 15946 => 33276, - 15947 => 33285, 15948 => 21646, 15949 => 23601, 15950 => 30106, 15951 => 38816, - 15952 => 25304, 15953 => 29401, 15954 => 30141, 15955 => 23621, 15956 => 39545, - 15957 => 33738, 15958 => 23616, 15959 => 21632, 15960 => 30697, 15961 => 20030, - 15962 => 27822, 15963 => 32858, 15964 => 25298, 15965 => 25454, 15966 => 24040, - 15967 => 20855, 15968 => 36317, 15969 => 36382, 15970 => 38191, 15971 => 20465, - 15972 => 21477, 15973 => 24807, 15974 => 28844, 15975 => 21095, 15976 => 25424, - 15977 => 40515, 15978 => 23071, 15979 => 20518, 15980 => 30519, 15981 => 21367, - 15982 => 32482, 15983 => 25733, 15984 => 25899, 15985 => 25225, 15986 => 25496, - 15987 => 20500, 15988 => 29237, 15989 => 35273, 15990 => 20915, 15991 => 35776, - 15992 => 32477, 15993 => 22343, 15994 => 33740, 15995 => 38055, 15996 => 20891, - 15997 => 21531, 15998 => 23803, 16161 => 20426, 16162 => 31459, 16163 => 27994, - 16164 => 37089, 16165 => 39567, 16166 => 21888, 16167 => 21654, 16168 => 21345, - 16169 => 21679, 16170 => 24320, 16171 => 25577, 16172 => 26999, 16173 => 20975, - 16174 => 24936, 16175 => 21002, 16176 => 22570, 16177 => 21208, 16178 => 22350, - 16179 => 30733, 16180 => 30475, 16181 => 24247, 16182 => 24951, 16183 => 31968, - 16184 => 25179, 16185 => 25239, 16186 => 20130, 16187 => 28821, 16188 => 32771, - 16189 => 25335, 16190 => 28900, 16191 => 38752, 16192 => 22391, 16193 => 33499, - 16194 => 26607, 16195 => 26869, 16196 => 30933, 16197 => 39063, 16198 => 31185, - 16199 => 22771, 16200 => 21683, 16201 => 21487, 16202 => 28212, 16203 => 20811, - 16204 => 21051, 16205 => 23458, 16206 => 35838, 16207 => 32943, 16208 => 21827, - 16209 => 22438, 16210 => 24691, 16211 => 22353, 16212 => 21549, 16213 => 31354, - 16214 => 24656, 16215 => 23380, 16216 => 25511, 16217 => 25248, 16218 => 21475, - 16219 => 25187, 16220 => 23495, 16221 => 26543, 16222 => 21741, 16223 => 31391, - 16224 => 33510, 16225 => 37239, 16226 => 24211, 16227 => 35044, 16228 => 22840, - 16229 => 22446, 16230 => 25358, 16231 => 36328, 16232 => 33007, 16233 => 22359, - 16234 => 31607, 16235 => 20393, 16236 => 24555, 16237 => 23485, 16238 => 27454, - 16239 => 21281, 16240 => 31568, 16241 => 29378, 16242 => 26694, 16243 => 30719, - 16244 => 30518, 16245 => 26103, 16246 => 20917, 16247 => 20111, 16248 => 30420, - 16249 => 23743, 16250 => 31397, 16251 => 33909, 16252 => 22862, 16253 => 39745, - 16254 => 20608, 16417 => 39304, 16418 => 24871, 16419 => 28291, 16420 => 22372, - 16421 => 26118, 16422 => 25414, 16423 => 22256, 16424 => 25324, 16425 => 25193, - 16426 => 24275, 16427 => 38420, 16428 => 22403, 16429 => 25289, 16430 => 21895, - 16431 => 34593, 16432 => 33098, 16433 => 36771, 16434 => 21862, 16435 => 33713, - 16436 => 26469, 16437 => 36182, 16438 => 34013, 16439 => 23146, 16440 => 26639, - 16441 => 25318, 16442 => 31726, 16443 => 38417, 16444 => 20848, 16445 => 28572, - 16446 => 35888, 16447 => 25597, 16448 => 35272, 16449 => 25042, 16450 => 32518, - 16451 => 28866, 16452 => 28389, 16453 => 29701, 16454 => 27028, 16455 => 29436, - 16456 => 24266, 16457 => 37070, 16458 => 26391, 16459 => 28010, 16460 => 25438, - 16461 => 21171, 16462 => 29282, 16463 => 32769, 16464 => 20332, 16465 => 23013, - 16466 => 37226, 16467 => 28889, 16468 => 28061, 16469 => 21202, 16470 => 20048, - 16471 => 38647, 16472 => 38253, 16473 => 34174, 16474 => 30922, 16475 => 32047, - 16476 => 20769, 16477 => 22418, 16478 => 25794, 16479 => 32907, 16480 => 31867, - 16481 => 27882, 16482 => 26865, 16483 => 26974, 16484 => 20919, 16485 => 21400, - 16486 => 26792, 16487 => 29313, 16488 => 40654, 16489 => 31729, 16490 => 29432, - 16491 => 31163, 16492 => 28435, 16493 => 29702, 16494 => 26446, 16495 => 37324, - 16496 => 40100, 16497 => 31036, 16498 => 33673, 16499 => 33620, 16500 => 21519, - 16501 => 26647, 16502 => 20029, 16503 => 21385, 16504 => 21169, 16505 => 30782, - 16506 => 21382, 16507 => 21033, 16508 => 20616, 16509 => 20363, 16510 => 20432, - 16673 => 30178, 16674 => 31435, 16675 => 31890, 16676 => 27813, 16677 => 38582, - 16678 => 21147, 16679 => 29827, 16680 => 21737, 16681 => 20457, 16682 => 32852, - 16683 => 33714, 16684 => 36830, 16685 => 38256, 16686 => 24265, 16687 => 24604, - 16688 => 28063, 16689 => 24088, 16690 => 25947, 16691 => 33080, 16692 => 38142, - 16693 => 24651, 16694 => 28860, 16695 => 32451, 16696 => 31918, 16697 => 20937, - 16698 => 26753, 16699 => 31921, 16700 => 33391, 16701 => 20004, 16702 => 36742, - 16703 => 37327, 16704 => 26238, 16705 => 20142, 16706 => 35845, 16707 => 25769, - 16708 => 32842, 16709 => 20698, 16710 => 30103, 16711 => 29134, 16712 => 23525, - 16713 => 36797, 16714 => 28518, 16715 => 20102, 16716 => 25730, 16717 => 38243, - 16718 => 24278, 16719 => 26009, 16720 => 21015, 16721 => 35010, 16722 => 28872, - 16723 => 21155, 16724 => 29454, 16725 => 29747, 16726 => 26519, 16727 => 30967, - 16728 => 38678, 16729 => 20020, 16730 => 37051, 16731 => 40158, 16732 => 28107, - 16733 => 20955, 16734 => 36161, 16735 => 21533, 16736 => 25294, 16737 => 29618, - 16738 => 33777, 16739 => 38646, 16740 => 40836, 16741 => 38083, 16742 => 20278, - 16743 => 32666, 16744 => 20940, 16745 => 28789, 16746 => 38517, 16747 => 23725, - 16748 => 39046, 16749 => 21478, 16750 => 20196, 16751 => 28316, 16752 => 29705, - 16753 => 27060, 16754 => 30827, 16755 => 39311, 16756 => 30041, 16757 => 21016, - 16758 => 30244, 16759 => 27969, 16760 => 26611, 16761 => 20845, 16762 => 40857, - 16763 => 32843, 16764 => 21657, 16765 => 31548, 16766 => 31423, 16929 => 38534, - 16930 => 22404, 16931 => 25314, 16932 => 38471, 16933 => 27004, 16934 => 23044, - 16935 => 25602, 16936 => 31699, 16937 => 28431, 16938 => 38475, 16939 => 33446, - 16940 => 21346, 16941 => 39045, 16942 => 24208, 16943 => 28809, 16944 => 25523, - 16945 => 21348, 16946 => 34383, 16947 => 40065, 16948 => 40595, 16949 => 30860, - 16950 => 38706, 16951 => 36335, 16952 => 36162, 16953 => 40575, 16954 => 28510, - 16955 => 31108, 16956 => 24405, 16957 => 38470, 16958 => 25134, 16959 => 39540, - 16960 => 21525, 16961 => 38109, 16962 => 20387, 16963 => 26053, 16964 => 23653, - 16965 => 23649, 16966 => 32533, 16967 => 34385, 16968 => 27695, 16969 => 24459, - 16970 => 29575, 16971 => 28388, 16972 => 32511, 16973 => 23782, 16974 => 25371, - 16975 => 23402, 16976 => 28390, 16977 => 21365, 16978 => 20081, 16979 => 25504, - 16980 => 30053, 16981 => 25249, 16982 => 36718, 16983 => 20262, 16984 => 20177, - 16985 => 27814, 16986 => 32438, 16987 => 35770, 16988 => 33821, 16989 => 34746, - 16990 => 32599, 16991 => 36923, 16992 => 38179, 16993 => 31657, 16994 => 39585, - 16995 => 35064, 16996 => 33853, 16997 => 27931, 16998 => 39558, 16999 => 32476, - 17000 => 22920, 17001 => 40635, 17002 => 29595, 17003 => 30721, 17004 => 34434, - 17005 => 39532, 17006 => 39554, 17007 => 22043, 17008 => 21527, 17009 => 22475, - 17010 => 20080, 17011 => 40614, 17012 => 21334, 17013 => 36808, 17014 => 33033, - 17015 => 30610, 17016 => 39314, 17017 => 34542, 17018 => 28385, 17019 => 34067, - 17020 => 26364, 17021 => 24930, 17022 => 28459, 17185 => 35881, 17186 => 33426, - 17187 => 33579, 17188 => 30450, 17189 => 27667, 17190 => 24537, 17191 => 33725, - 17192 => 29483, 17193 => 33541, 17194 => 38170, 17195 => 27611, 17196 => 30683, - 17197 => 38086, 17198 => 21359, 17199 => 33538, 17200 => 20882, 17201 => 24125, - 17202 => 35980, 17203 => 36152, 17204 => 20040, 17205 => 29611, 17206 => 26522, - 17207 => 26757, 17208 => 37238, 17209 => 38665, 17210 => 29028, 17211 => 27809, - 17212 => 30473, 17213 => 23186, 17214 => 38209, 17215 => 27599, 17216 => 32654, - 17217 => 26151, 17218 => 23504, 17219 => 22969, 17220 => 23194, 17221 => 38376, - 17222 => 38391, 17223 => 20204, 17224 => 33804, 17225 => 33945, 17226 => 27308, - 17227 => 30431, 17228 => 38192, 17229 => 29467, 17230 => 26790, 17231 => 23391, - 17232 => 30511, 17233 => 37274, 17234 => 38753, 17235 => 31964, 17236 => 36855, - 17237 => 35868, 17238 => 24357, 17239 => 31859, 17240 => 31192, 17241 => 35269, - 17242 => 27852, 17243 => 34588, 17244 => 23494, 17245 => 24130, 17246 => 26825, - 17247 => 30496, 17248 => 32501, 17249 => 20885, 17250 => 20813, 17251 => 21193, - 17252 => 23081, 17253 => 32517, 17254 => 38754, 17255 => 33495, 17256 => 25551, - 17257 => 30596, 17258 => 34256, 17259 => 31186, 17260 => 28218, 17261 => 24217, - 17262 => 22937, 17263 => 34065, 17264 => 28781, 17265 => 27665, 17266 => 25279, - 17267 => 30399, 17268 => 25935, 17269 => 24751, 17270 => 38397, 17271 => 26126, - 17272 => 34719, 17273 => 40483, 17274 => 38125, 17275 => 21517, 17276 => 21629, - 17277 => 35884, 17278 => 25720, 17441 => 25721, 17442 => 34321, 17443 => 27169, - 17444 => 33180, 17445 => 30952, 17446 => 25705, 17447 => 39764, 17448 => 25273, - 17449 => 26411, 17450 => 33707, 17451 => 22696, 17452 => 40664, 17453 => 27819, - 17454 => 28448, 17455 => 23518, 17456 => 38476, 17457 => 35851, 17458 => 29279, - 17459 => 26576, 17460 => 25287, 17461 => 29281, 17462 => 20137, 17463 => 22982, - 17464 => 27597, 17465 => 22675, 17466 => 26286, 17467 => 24149, 17468 => 21215, - 17469 => 24917, 17470 => 26408, 17471 => 30446, 17472 => 30566, 17473 => 29287, - 17474 => 31302, 17475 => 25343, 17476 => 21738, 17477 => 21584, 17478 => 38048, - 17479 => 37027, 17480 => 23068, 17481 => 32435, 17482 => 27670, 17483 => 20035, - 17484 => 22902, 17485 => 32784, 17486 => 22856, 17487 => 21335, 17488 => 30007, - 17489 => 38590, 17490 => 22218, 17491 => 25376, 17492 => 33041, 17493 => 24700, - 17494 => 38393, 17495 => 28118, 17496 => 21602, 17497 => 39297, 17498 => 20869, - 17499 => 23273, 17500 => 33021, 17501 => 22958, 17502 => 38675, 17503 => 20522, - 17504 => 27877, 17505 => 23612, 17506 => 25311, 17507 => 20320, 17508 => 21311, - 17509 => 33147, 17510 => 36870, 17511 => 28346, 17512 => 34091, 17513 => 25288, - 17514 => 24180, 17515 => 30910, 17516 => 25781, 17517 => 25467, 17518 => 24565, - 17519 => 23064, 17520 => 37247, 17521 => 40479, 17522 => 23615, 17523 => 25423, - 17524 => 32834, 17525 => 23421, 17526 => 21870, 17527 => 38218, 17528 => 38221, - 17529 => 28037, 17530 => 24744, 17531 => 26592, 17532 => 29406, 17533 => 20957, - 17534 => 23425, 17697 => 25319, 17698 => 27870, 17699 => 29275, 17700 => 25197, - 17701 => 38062, 17702 => 32445, 17703 => 33043, 17704 => 27987, 17705 => 20892, - 17706 => 24324, 17707 => 22900, 17708 => 21162, 17709 => 24594, 17710 => 22899, - 17711 => 26262, 17712 => 34384, 17713 => 30111, 17714 => 25386, 17715 => 25062, - 17716 => 31983, 17717 => 35834, 17718 => 21734, 17719 => 27431, 17720 => 40485, - 17721 => 27572, 17722 => 34261, 17723 => 21589, 17724 => 20598, 17725 => 27812, - 17726 => 21866, 17727 => 36276, 17728 => 29228, 17729 => 24085, 17730 => 24597, - 17731 => 29750, 17732 => 25293, 17733 => 25490, 17734 => 29260, 17735 => 24472, - 17736 => 28227, 17737 => 27966, 17738 => 25856, 17739 => 28504, 17740 => 30424, - 17741 => 30928, 17742 => 30460, 17743 => 30036, 17744 => 21028, 17745 => 21467, - 17746 => 20051, 17747 => 24222, 17748 => 26049, 17749 => 32810, 17750 => 32982, - 17751 => 25243, 17752 => 21638, 17753 => 21032, 17754 => 28846, 17755 => 34957, - 17756 => 36305, 17757 => 27873, 17758 => 21624, 17759 => 32986, 17760 => 22521, - 17761 => 35060, 17762 => 36180, 17763 => 38506, 17764 => 37197, 17765 => 20329, - 17766 => 27803, 17767 => 21943, 17768 => 30406, 17769 => 30768, 17770 => 25256, - 17771 => 28921, 17772 => 28558, 17773 => 24429, 17774 => 34028, 17775 => 26842, - 17776 => 30844, 17777 => 31735, 17778 => 33192, 17779 => 26379, 17780 => 40527, - 17781 => 25447, 17782 => 30896, 17783 => 22383, 17784 => 30738, 17785 => 38713, - 17786 => 25209, 17787 => 25259, 17788 => 21128, 17789 => 29749, 17790 => 27607, - 17953 => 21860, 17954 => 33086, 17955 => 30130, 17956 => 30382, 17957 => 21305, - 17958 => 30174, 17959 => 20731, 17960 => 23617, 17961 => 35692, 17962 => 31687, - 17963 => 20559, 17964 => 29255, 17965 => 39575, 17966 => 39128, 17967 => 28418, - 17968 => 29922, 17969 => 31080, 17970 => 25735, 17971 => 30629, 17972 => 25340, - 17973 => 39057, 17974 => 36139, 17975 => 21697, 17976 => 32856, 17977 => 20050, - 17978 => 22378, 17979 => 33529, 17980 => 33805, 17981 => 24179, 17982 => 20973, - 17983 => 29942, 17984 => 35780, 17985 => 23631, 17986 => 22369, 17987 => 27900, - 17988 => 39047, 17989 => 23110, 17990 => 30772, 17991 => 39748, 17992 => 36843, - 17993 => 31893, 17994 => 21078, 17995 => 25169, 17996 => 38138, 17997 => 20166, - 17998 => 33670, 17999 => 33889, 18000 => 33769, 18001 => 33970, 18002 => 22484, - 18003 => 26420, 18004 => 22275, 18005 => 26222, 18006 => 28006, 18007 => 35889, - 18008 => 26333, 18009 => 28689, 18010 => 26399, 18011 => 27450, 18012 => 26646, - 18013 => 25114, 18014 => 22971, 18015 => 19971, 18016 => 20932, 18017 => 28422, - 18018 => 26578, 18019 => 27791, 18020 => 20854, 18021 => 26827, 18022 => 22855, - 18023 => 27495, 18024 => 30054, 18025 => 23822, 18026 => 33040, 18027 => 40784, - 18028 => 26071, 18029 => 31048, 18030 => 31041, 18031 => 39569, 18032 => 36215, - 18033 => 23682, 18034 => 20062, 18035 => 20225, 18036 => 21551, 18037 => 22865, - 18038 => 30732, 18039 => 22120, 18040 => 27668, 18041 => 36804, 18042 => 24323, - 18043 => 27773, 18044 => 27875, 18045 => 35755, 18046 => 25488, 18209 => 24688, - 18210 => 27965, 18211 => 29301, 18212 => 25190, 18213 => 38030, 18214 => 38085, - 18215 => 21315, 18216 => 36801, 18217 => 31614, 18218 => 20191, 18219 => 35878, - 18220 => 20094, 18221 => 40660, 18222 => 38065, 18223 => 38067, 18224 => 21069, - 18225 => 28508, 18226 => 36963, 18227 => 27973, 18228 => 35892, 18229 => 22545, - 18230 => 23884, 18231 => 27424, 18232 => 27465, 18233 => 26538, 18234 => 21595, - 18235 => 33108, 18236 => 32652, 18237 => 22681, 18238 => 34103, 18239 => 24378, - 18240 => 25250, 18241 => 27207, 18242 => 38201, 18243 => 25970, 18244 => 24708, - 18245 => 26725, 18246 => 30631, 18247 => 20052, 18248 => 20392, 18249 => 24039, - 18250 => 38808, 18251 => 25772, 18252 => 32728, 18253 => 23789, 18254 => 20431, - 18255 => 31373, 18256 => 20999, 18257 => 33540, 18258 => 19988, 18259 => 24623, - 18260 => 31363, 18261 => 38054, 18262 => 20405, 18263 => 20146, 18264 => 31206, - 18265 => 29748, 18266 => 21220, 18267 => 33465, 18268 => 25810, 18269 => 31165, - 18270 => 23517, 18271 => 27777, 18272 => 38738, 18273 => 36731, 18274 => 27682, - 18275 => 20542, 18276 => 21375, 18277 => 28165, 18278 => 25806, 18279 => 26228, - 18280 => 27696, 18281 => 24773, 18282 => 39031, 18283 => 35831, 18284 => 24198, - 18285 => 29756, 18286 => 31351, 18287 => 31179, 18288 => 19992, 18289 => 37041, - 18290 => 29699, 18291 => 27714, 18292 => 22234, 18293 => 37195, 18294 => 27845, - 18295 => 36235, 18296 => 21306, 18297 => 34502, 18298 => 26354, 18299 => 36527, - 18300 => 23624, 18301 => 39537, 18302 => 28192, 18465 => 21462, 18466 => 23094, - 18467 => 40843, 18468 => 36259, 18469 => 21435, 18470 => 22280, 18471 => 39079, - 18472 => 26435, 18473 => 37275, 18474 => 27849, 18475 => 20840, 18476 => 30154, - 18477 => 25331, 18478 => 29356, 18479 => 21048, 18480 => 21149, 18481 => 32570, - 18482 => 28820, 18483 => 30264, 18484 => 21364, 18485 => 40522, 18486 => 27063, - 18487 => 30830, 18488 => 38592, 18489 => 35033, 18490 => 32676, 18491 => 28982, - 18492 => 29123, 18493 => 20873, 18494 => 26579, 18495 => 29924, 18496 => 22756, - 18497 => 25880, 18498 => 22199, 18499 => 35753, 18500 => 39286, 18501 => 25200, - 18502 => 32469, 18503 => 24825, 18504 => 28909, 18505 => 22764, 18506 => 20161, - 18507 => 20154, 18508 => 24525, 18509 => 38887, 18510 => 20219, 18511 => 35748, - 18512 => 20995, 18513 => 22922, 18514 => 32427, 18515 => 25172, 18516 => 20173, - 18517 => 26085, 18518 => 25102, 18519 => 33592, 18520 => 33993, 18521 => 33635, - 18522 => 34701, 18523 => 29076, 18524 => 28342, 18525 => 23481, 18526 => 32466, - 18527 => 20887, 18528 => 25545, 18529 => 26580, 18530 => 32905, 18531 => 33593, - 18532 => 34837, 18533 => 20754, 18534 => 23418, 18535 => 22914, 18536 => 36785, - 18537 => 20083, 18538 => 27741, 18539 => 20837, 18540 => 35109, 18541 => 36719, - 18542 => 38446, 18543 => 34122, 18544 => 29790, 18545 => 38160, 18546 => 38384, - 18547 => 28070, 18548 => 33509, 18549 => 24369, 18550 => 25746, 18551 => 27922, - 18552 => 33832, 18553 => 33134, 18554 => 40131, 18555 => 22622, 18556 => 36187, - 18557 => 19977, 18558 => 21441, 18721 => 20254, 18722 => 25955, 18723 => 26705, - 18724 => 21971, 18725 => 20007, 18726 => 25620, 18727 => 39578, 18728 => 25195, - 18729 => 23234, 18730 => 29791, 18731 => 33394, 18732 => 28073, 18733 => 26862, - 18734 => 20711, 18735 => 33678, 18736 => 30722, 18737 => 26432, 18738 => 21049, - 18739 => 27801, 18740 => 32433, 18741 => 20667, 18742 => 21861, 18743 => 29022, - 18744 => 31579, 18745 => 26194, 18746 => 29642, 18747 => 33515, 18748 => 26441, - 18749 => 23665, 18750 => 21024, 18751 => 29053, 18752 => 34923, 18753 => 38378, - 18754 => 38485, 18755 => 25797, 18756 => 36193, 18757 => 33203, 18758 => 21892, - 18759 => 27733, 18760 => 25159, 18761 => 32558, 18762 => 22674, 18763 => 20260, - 18764 => 21830, 18765 => 36175, 18766 => 26188, 18767 => 19978, 18768 => 23578, - 18769 => 35059, 18770 => 26786, 18771 => 25422, 18772 => 31245, 18773 => 28903, - 18774 => 33421, 18775 => 21242, 18776 => 38902, 18777 => 23569, 18778 => 21736, - 18779 => 37045, 18780 => 32461, 18781 => 22882, 18782 => 36170, 18783 => 34503, - 18784 => 33292, 18785 => 33293, 18786 => 36198, 18787 => 25668, 18788 => 23556, - 18789 => 24913, 18790 => 28041, 18791 => 31038, 18792 => 35774, 18793 => 30775, - 18794 => 30003, 18795 => 21627, 18796 => 20280, 18797 => 36523, 18798 => 28145, - 18799 => 23072, 18800 => 32453, 18801 => 31070, 18802 => 27784, 18803 => 23457, - 18804 => 23158, 18805 => 29978, 18806 => 32958, 18807 => 24910, 18808 => 28183, - 18809 => 22768, 18810 => 29983, 18811 => 29989, 18812 => 29298, 18813 => 21319, - 18814 => 32499, 18977 => 30465, 18978 => 30427, 18979 => 21097, 18980 => 32988, - 18981 => 22307, 18982 => 24072, 18983 => 22833, 18984 => 29422, 18985 => 26045, - 18986 => 28287, 18987 => 35799, 18988 => 23608, 18989 => 34417, 18990 => 21313, - 18991 => 30707, 18992 => 25342, 18993 => 26102, 18994 => 20160, 18995 => 39135, - 18996 => 34432, 18997 => 23454, 18998 => 35782, 18999 => 21490, 19000 => 30690, - 19001 => 20351, 19002 => 23630, 19003 => 39542, 19004 => 22987, 19005 => 24335, - 19006 => 31034, 19007 => 22763, 19008 => 19990, 19009 => 26623, 19010 => 20107, - 19011 => 25325, 19012 => 35475, 19013 => 36893, 19014 => 21183, 19015 => 26159, - 19016 => 21980, 19017 => 22124, 19018 => 36866, 19019 => 20181, 19020 => 20365, - 19021 => 37322, 19022 => 39280, 19023 => 27663, 19024 => 24066, 19025 => 24643, - 19026 => 23460, 19027 => 35270, 19028 => 35797, 19029 => 25910, 19030 => 25163, - 19031 => 39318, 19032 => 23432, 19033 => 23551, 19034 => 25480, 19035 => 21806, - 19036 => 21463, 19037 => 30246, 19038 => 20861, 19039 => 34092, 19040 => 26530, - 19041 => 26803, 19042 => 27530, 19043 => 25234, 19044 => 36755, 19045 => 21460, - 19046 => 33298, 19047 => 28113, 19048 => 30095, 19049 => 20070, 19050 => 36174, - 19051 => 23408, 19052 => 29087, 19053 => 34223, 19054 => 26257, 19055 => 26329, - 19056 => 32626, 19057 => 34560, 19058 => 40653, 19059 => 40736, 19060 => 23646, - 19061 => 26415, 19062 => 36848, 19063 => 26641, 19064 => 26463, 19065 => 25101, - 19066 => 31446, 19067 => 22661, 19068 => 24246, 19069 => 25968, 19070 => 28465, - 19233 => 24661, 19234 => 21047, 19235 => 32781, 19236 => 25684, 19237 => 34928, - 19238 => 29993, 19239 => 24069, 19240 => 26643, 19241 => 25332, 19242 => 38684, - 19243 => 21452, 19244 => 29245, 19245 => 35841, 19246 => 27700, 19247 => 30561, - 19248 => 31246, 19249 => 21550, 19250 => 30636, 19251 => 39034, 19252 => 33308, - 19253 => 35828, 19254 => 30805, 19255 => 26388, 19256 => 28865, 19257 => 26031, - 19258 => 25749, 19259 => 22070, 19260 => 24605, 19261 => 31169, 19262 => 21496, - 19263 => 19997, 19264 => 27515, 19265 => 32902, 19266 => 23546, 19267 => 21987, - 19268 => 22235, 19269 => 20282, 19270 => 20284, 19271 => 39282, 19272 => 24051, - 19273 => 26494, 19274 => 32824, 19275 => 24578, 19276 => 39042, 19277 => 36865, - 19278 => 23435, 19279 => 35772, 19280 => 35829, 19281 => 25628, 19282 => 33368, - 19283 => 25822, 19284 => 22013, 19285 => 33487, 19286 => 37221, 19287 => 20439, - 19288 => 32032, 19289 => 36895, 19290 => 31903, 19291 => 20723, 19292 => 22609, - 19293 => 28335, 19294 => 23487, 19295 => 35785, 19296 => 32899, 19297 => 37240, - 19298 => 33948, 19299 => 31639, 19300 => 34429, 19301 => 38539, 19302 => 38543, - 19303 => 32485, 19304 => 39635, 19305 => 30862, 19306 => 23681, 19307 => 31319, - 19308 => 36930, 19309 => 38567, 19310 => 31071, 19311 => 23385, 19312 => 25439, - 19313 => 31499, 19314 => 34001, 19315 => 26797, 19316 => 21766, 19317 => 32553, - 19318 => 29712, 19319 => 32034, 19320 => 38145, 19321 => 25152, 19322 => 22604, - 19323 => 20182, 19324 => 23427, 19325 => 22905, 19326 => 22612, 19489 => 29549, - 19490 => 25374, 19491 => 36427, 19492 => 36367, 19493 => 32974, 19494 => 33492, - 19495 => 25260, 19496 => 21488, 19497 => 27888, 19498 => 37214, 19499 => 22826, - 19500 => 24577, 19501 => 27760, 19502 => 22349, 19503 => 25674, 19504 => 36138, - 19505 => 30251, 19506 => 28393, 19507 => 22363, 19508 => 27264, 19509 => 30192, - 19510 => 28525, 19511 => 35885, 19512 => 35848, 19513 => 22374, 19514 => 27631, - 19515 => 34962, 19516 => 30899, 19517 => 25506, 19518 => 21497, 19519 => 28845, - 19520 => 27748, 19521 => 22616, 19522 => 25642, 19523 => 22530, 19524 => 26848, - 19525 => 33179, 19526 => 21776, 19527 => 31958, 19528 => 20504, 19529 => 36538, - 19530 => 28108, 19531 => 36255, 19532 => 28907, 19533 => 25487, 19534 => 28059, - 19535 => 28372, 19536 => 32486, 19537 => 33796, 19538 => 26691, 19539 => 36867, - 19540 => 28120, 19541 => 38518, 19542 => 35752, 19543 => 22871, 19544 => 29305, - 19545 => 34276, 19546 => 33150, 19547 => 30140, 19548 => 35466, 19549 => 26799, - 19550 => 21076, 19551 => 36386, 19552 => 38161, 19553 => 25552, 19554 => 39064, - 19555 => 36420, 19556 => 21884, 19557 => 20307, 19558 => 26367, 19559 => 22159, - 19560 => 24789, 19561 => 28053, 19562 => 21059, 19563 => 23625, 19564 => 22825, - 19565 => 28155, 19566 => 22635, 19567 => 30000, 19568 => 29980, 19569 => 24684, - 19570 => 33300, 19571 => 33094, 19572 => 25361, 19573 => 26465, 19574 => 36834, - 19575 => 30522, 19576 => 36339, 19577 => 36148, 19578 => 38081, 19579 => 24086, - 19580 => 21381, 19581 => 21548, 19582 => 28867, 19745 => 27712, 19746 => 24311, - 19747 => 20572, 19748 => 20141, 19749 => 24237, 19750 => 25402, 19751 => 33351, - 19752 => 36890, 19753 => 26704, 19754 => 37230, 19755 => 30643, 19756 => 21516, - 19757 => 38108, 19758 => 24420, 19759 => 31461, 19760 => 26742, 19761 => 25413, - 19762 => 31570, 19763 => 32479, 19764 => 30171, 19765 => 20599, 19766 => 25237, - 19767 => 22836, 19768 => 36879, 19769 => 20984, 19770 => 31171, 19771 => 31361, - 19772 => 22270, 19773 => 24466, 19774 => 36884, 19775 => 28034, 19776 => 23648, - 19777 => 22303, 19778 => 21520, 19779 => 20820, 19780 => 28237, 19781 => 22242, - 19782 => 25512, 19783 => 39059, 19784 => 33151, 19785 => 34581, 19786 => 35114, - 19787 => 36864, 19788 => 21534, 19789 => 23663, 19790 => 33216, 19791 => 25302, - 19792 => 25176, 19793 => 33073, 19794 => 40501, 19795 => 38464, 19796 => 39534, - 19797 => 39548, 19798 => 26925, 19799 => 22949, 19800 => 25299, 19801 => 21822, - 19802 => 25366, 19803 => 21703, 19804 => 34521, 19805 => 27964, 19806 => 23043, - 19807 => 29926, 19808 => 34972, 19809 => 27498, 19810 => 22806, 19811 => 35916, - 19812 => 24367, 19813 => 28286, 19814 => 29609, 19815 => 39037, 19816 => 20024, - 19817 => 28919, 19818 => 23436, 19819 => 30871, 19820 => 25405, 19821 => 26202, - 19822 => 30358, 19823 => 24779, 19824 => 23451, 19825 => 23113, 19826 => 19975, - 19827 => 33109, 19828 => 27754, 19829 => 29579, 19830 => 20129, 19831 => 26505, - 19832 => 32593, 19833 => 24448, 19834 => 26106, 19835 => 26395, 19836 => 24536, - 19837 => 22916, 19838 => 23041, 20001 => 24013, 20002 => 24494, 20003 => 21361, - 20004 => 38886, 20005 => 36829, 20006 => 26693, 20007 => 22260, 20008 => 21807, - 20009 => 24799, 20010 => 20026, 20011 => 28493, 20012 => 32500, 20013 => 33479, - 20014 => 33806, 20015 => 22996, 20016 => 20255, 20017 => 20266, 20018 => 23614, - 20019 => 32428, 20020 => 26410, 20021 => 34074, 20022 => 21619, 20023 => 30031, - 20024 => 32963, 20025 => 21890, 20026 => 39759, 20027 => 20301, 20028 => 28205, - 20029 => 35859, 20030 => 23561, 20031 => 24944, 20032 => 21355, 20033 => 30239, - 20034 => 28201, 20035 => 34442, 20036 => 25991, 20037 => 38395, 20038 => 32441, - 20039 => 21563, 20040 => 31283, 20041 => 32010, 20042 => 38382, 20043 => 21985, - 20044 => 32705, 20045 => 29934, 20046 => 25373, 20047 => 34583, 20048 => 28065, - 20049 => 31389, 20050 => 25105, 20051 => 26017, 20052 => 21351, 20053 => 25569, - 20054 => 27779, 20055 => 24043, 20056 => 21596, 20057 => 38056, 20058 => 20044, - 20059 => 27745, 20060 => 35820, 20061 => 23627, 20062 => 26080, 20063 => 33436, - 20064 => 26791, 20065 => 21566, 20066 => 21556, 20067 => 27595, 20068 => 27494, - 20069 => 20116, 20070 => 25410, 20071 => 21320, 20072 => 33310, 20073 => 20237, - 20074 => 20398, 20075 => 22366, 20076 => 25098, 20077 => 38654, 20078 => 26212, - 20079 => 29289, 20080 => 21247, 20081 => 21153, 20082 => 24735, 20083 => 35823, - 20084 => 26132, 20085 => 29081, 20086 => 26512, 20087 => 35199, 20088 => 30802, - 20089 => 30717, 20090 => 26224, 20091 => 22075, 20092 => 21560, 20093 => 38177, - 20094 => 29306, 20257 => 31232, 20258 => 24687, 20259 => 24076, 20260 => 24713, - 20261 => 33181, 20262 => 22805, 20263 => 24796, 20264 => 29060, 20265 => 28911, - 20266 => 28330, 20267 => 27728, 20268 => 29312, 20269 => 27268, 20270 => 34989, - 20271 => 24109, 20272 => 20064, 20273 => 23219, 20274 => 21916, 20275 => 38115, - 20276 => 27927, 20277 => 31995, 20278 => 38553, 20279 => 25103, 20280 => 32454, - 20281 => 30606, 20282 => 34430, 20283 => 21283, 20284 => 38686, 20285 => 36758, - 20286 => 26247, 20287 => 23777, 20288 => 20384, 20289 => 29421, 20290 => 19979, - 20291 => 21414, 20292 => 22799, 20293 => 21523, 20294 => 25472, 20295 => 38184, - 20296 => 20808, 20297 => 20185, 20298 => 40092, 20299 => 32420, 20300 => 21688, - 20301 => 36132, 20302 => 34900, 20303 => 33335, 20304 => 38386, 20305 => 28046, - 20306 => 24358, 20307 => 23244, 20308 => 26174, 20309 => 38505, 20310 => 29616, - 20311 => 29486, 20312 => 21439, 20313 => 33146, 20314 => 39301, 20315 => 32673, - 20316 => 23466, 20317 => 38519, 20318 => 38480, 20319 => 32447, 20320 => 30456, - 20321 => 21410, 20322 => 38262, 20323 => 39321, 20324 => 31665, 20325 => 35140, - 20326 => 28248, 20327 => 20065, 20328 => 32724, 20329 => 31077, 20330 => 35814, - 20331 => 24819, 20332 => 21709, 20333 => 20139, 20334 => 39033, 20335 => 24055, - 20336 => 27233, 20337 => 20687, 20338 => 21521, 20339 => 35937, 20340 => 33831, - 20341 => 30813, 20342 => 38660, 20343 => 21066, 20344 => 21742, 20345 => 22179, - 20346 => 38144, 20347 => 28040, 20348 => 23477, 20349 => 28102, 20350 => 26195, - 20513 => 23567, 20514 => 23389, 20515 => 26657, 20516 => 32918, 20517 => 21880, - 20518 => 31505, 20519 => 25928, 20520 => 26964, 20521 => 20123, 20522 => 27463, - 20523 => 34638, 20524 => 38795, 20525 => 21327, 20526 => 25375, 20527 => 25658, - 20528 => 37034, 20529 => 26012, 20530 => 32961, 20531 => 35856, 20532 => 20889, - 20533 => 26800, 20534 => 21368, 20535 => 34809, 20536 => 25032, 20537 => 27844, - 20538 => 27899, 20539 => 35874, 20540 => 23633, 20541 => 34218, 20542 => 33455, - 20543 => 38156, 20544 => 27427, 20545 => 36763, 20546 => 26032, 20547 => 24571, - 20548 => 24515, 20549 => 20449, 20550 => 34885, 20551 => 26143, 20552 => 33125, - 20553 => 29481, 20554 => 24826, 20555 => 20852, 20556 => 21009, 20557 => 22411, - 20558 => 24418, 20559 => 37026, 20560 => 34892, 20561 => 37266, 20562 => 24184, - 20563 => 26447, 20564 => 24615, 20565 => 22995, 20566 => 20804, 20567 => 20982, - 20568 => 33016, 20569 => 21256, 20570 => 27769, 20571 => 38596, 20572 => 29066, - 20573 => 20241, 20574 => 20462, 20575 => 32670, 20576 => 26429, 20577 => 21957, - 20578 => 38152, 20579 => 31168, 20580 => 34966, 20581 => 32483, 20582 => 22687, - 20583 => 25100, 20584 => 38656, 20585 => 34394, 20586 => 22040, 20587 => 39035, - 20588 => 24464, 20589 => 35768, 20590 => 33988, 20591 => 37207, 20592 => 21465, - 20593 => 26093, 20594 => 24207, 20595 => 30044, 20596 => 24676, 20597 => 32110, - 20598 => 23167, 20599 => 32490, 20600 => 32493, 20601 => 36713, 20602 => 21927, - 20603 => 23459, 20604 => 24748, 20605 => 26059, 20606 => 29572, 20769 => 36873, - 20770 => 30307, 20771 => 30505, 20772 => 32474, 20773 => 38772, 20774 => 34203, - 20775 => 23398, 20776 => 31348, 20777 => 38634, 20778 => 34880, 20779 => 21195, - 20780 => 29071, 20781 => 24490, 20782 => 26092, 20783 => 35810, 20784 => 23547, - 20785 => 39535, 20786 => 24033, 20787 => 27529, 20788 => 27739, 20789 => 35757, - 20790 => 35759, 20791 => 36874, 20792 => 36805, 20793 => 21387, 20794 => 25276, - 20795 => 40486, 20796 => 40493, 20797 => 21568, 20798 => 20011, 20799 => 33469, - 20800 => 29273, 20801 => 34460, 20802 => 23830, 20803 => 34905, 20804 => 28079, - 20805 => 38597, 20806 => 21713, 20807 => 20122, 20808 => 35766, 20809 => 28937, - 20810 => 21693, 20811 => 38409, 20812 => 28895, 20813 => 28153, 20814 => 30416, - 20815 => 20005, 20816 => 30740, 20817 => 34578, 20818 => 23721, 20819 => 24310, - 20820 => 35328, 20821 => 39068, 20822 => 38414, 20823 => 28814, 20824 => 27839, - 20825 => 22852, 20826 => 25513, 20827 => 30524, 20828 => 34893, 20829 => 28436, - 20830 => 33395, 20831 => 22576, 20832 => 29141, 20833 => 21388, 20834 => 30746, - 20835 => 38593, 20836 => 21761, 20837 => 24422, 20838 => 28976, 20839 => 23476, - 20840 => 35866, 20841 => 39564, 20842 => 27523, 20843 => 22830, 20844 => 40495, - 20845 => 31207, 20846 => 26472, 20847 => 25196, 20848 => 20335, 20849 => 30113, - 20850 => 32650, 20851 => 27915, 20852 => 38451, 20853 => 27687, 20854 => 20208, - 20855 => 30162, 20856 => 20859, 20857 => 26679, 20858 => 28478, 20859 => 36992, - 20860 => 33136, 20861 => 22934, 20862 => 29814, 21025 => 25671, 21026 => 23591, - 21027 => 36965, 21028 => 31377, 21029 => 35875, 21030 => 23002, 21031 => 21676, - 21032 => 33280, 21033 => 33647, 21034 => 35201, 21035 => 32768, 21036 => 26928, - 21037 => 22094, 21038 => 32822, 21039 => 29239, 21040 => 37326, 21041 => 20918, - 21042 => 20063, 21043 => 39029, 21044 => 25494, 21045 => 19994, 21046 => 21494, - 21047 => 26355, 21048 => 33099, 21049 => 22812, 21050 => 28082, 21051 => 19968, - 21052 => 22777, 21053 => 21307, 21054 => 25558, 21055 => 38129, 21056 => 20381, - 21057 => 20234, 21058 => 34915, 21059 => 39056, 21060 => 22839, 21061 => 36951, - 21062 => 31227, 21063 => 20202, 21064 => 33008, 21065 => 30097, 21066 => 27778, - 21067 => 23452, 21068 => 23016, 21069 => 24413, 21070 => 26885, 21071 => 34433, - 21072 => 20506, 21073 => 24050, 21074 => 20057, 21075 => 30691, 21076 => 20197, - 21077 => 33402, 21078 => 25233, 21079 => 26131, 21080 => 37009, 21081 => 23673, - 21082 => 20159, 21083 => 24441, 21084 => 33222, 21085 => 36920, 21086 => 32900, - 21087 => 30123, 21088 => 20134, 21089 => 35028, 21090 => 24847, 21091 => 27589, - 21092 => 24518, 21093 => 20041, 21094 => 30410, 21095 => 28322, 21096 => 35811, - 21097 => 35758, 21098 => 35850, 21099 => 35793, 21100 => 24322, 21101 => 32764, - 21102 => 32716, 21103 => 32462, 21104 => 33589, 21105 => 33643, 21106 => 22240, - 21107 => 27575, 21108 => 38899, 21109 => 38452, 21110 => 23035, 21111 => 21535, - 21112 => 38134, 21113 => 28139, 21114 => 23493, 21115 => 39278, 21116 => 23609, - 21117 => 24341, 21118 => 38544, 21281 => 21360, 21282 => 33521, 21283 => 27185, - 21284 => 23156, 21285 => 40560, 21286 => 24212, 21287 => 32552, 21288 => 33721, - 21289 => 33828, 21290 => 33829, 21291 => 33639, 21292 => 34631, 21293 => 36814, - 21294 => 36194, 21295 => 30408, 21296 => 24433, 21297 => 39062, 21298 => 30828, - 21299 => 26144, 21300 => 21727, 21301 => 25317, 21302 => 20323, 21303 => 33219, - 21304 => 30152, 21305 => 24248, 21306 => 38605, 21307 => 36362, 21308 => 34553, - 21309 => 21647, 21310 => 27891, 21311 => 28044, 21312 => 27704, 21313 => 24703, - 21314 => 21191, 21315 => 29992, 21316 => 24189, 21317 => 20248, 21318 => 24736, - 21319 => 24551, 21320 => 23588, 21321 => 30001, 21322 => 37038, 21323 => 38080, - 21324 => 29369, 21325 => 27833, 21326 => 28216, 21327 => 37193, 21328 => 26377, - 21329 => 21451, 21330 => 21491, 21331 => 20305, 21332 => 37321, 21333 => 35825, - 21334 => 21448, 21335 => 24188, 21336 => 36802, 21337 => 28132, 21338 => 20110, - 21339 => 30402, 21340 => 27014, 21341 => 34398, 21342 => 24858, 21343 => 33286, - 21344 => 20313, 21345 => 20446, 21346 => 36926, 21347 => 40060, 21348 => 24841, - 21349 => 28189, 21350 => 28180, 21351 => 38533, 21352 => 20104, 21353 => 23089, - 21354 => 38632, 21355 => 19982, 21356 => 23679, 21357 => 31161, 21358 => 23431, - 21359 => 35821, 21360 => 32701, 21361 => 29577, 21362 => 22495, 21363 => 33419, - 21364 => 37057, 21365 => 21505, 21366 => 36935, 21367 => 21947, 21368 => 23786, - 21369 => 24481, 21370 => 24840, 21371 => 27442, 21372 => 29425, 21373 => 32946, - 21374 => 35465, 21537 => 28020, 21538 => 23507, 21539 => 35029, 21540 => 39044, - 21541 => 35947, 21542 => 39533, 21543 => 40499, 21544 => 28170, 21545 => 20900, - 21546 => 20803, 21547 => 22435, 21548 => 34945, 21549 => 21407, 21550 => 25588, - 21551 => 36757, 21552 => 22253, 21553 => 21592, 21554 => 22278, 21555 => 29503, - 21556 => 28304, 21557 => 32536, 21558 => 36828, 21559 => 33489, 21560 => 24895, - 21561 => 24616, 21562 => 38498, 21563 => 26352, 21564 => 32422, 21565 => 36234, - 21566 => 36291, 21567 => 38053, 21568 => 23731, 21569 => 31908, 21570 => 26376, - 21571 => 24742, 21572 => 38405, 21573 => 32792, 21574 => 20113, 21575 => 37095, - 21576 => 21248, 21577 => 38504, 21578 => 20801, 21579 => 36816, 21580 => 34164, - 21581 => 37213, 21582 => 26197, 21583 => 38901, 21584 => 23381, 21585 => 21277, - 21586 => 30776, 21587 => 26434, 21588 => 26685, 21589 => 21705, 21590 => 28798, - 21591 => 23472, 21592 => 36733, 21593 => 20877, 21594 => 22312, 21595 => 21681, - 21596 => 25874, 21597 => 26242, 21598 => 36190, 21599 => 36163, 21600 => 33039, - 21601 => 33900, 21602 => 36973, 21603 => 31967, 21604 => 20991, 21605 => 34299, - 21606 => 26531, 21607 => 26089, 21608 => 28577, 21609 => 34468, 21610 => 36481, - 21611 => 22122, 21612 => 36896, 21613 => 30338, 21614 => 28790, 21615 => 29157, - 21616 => 36131, 21617 => 25321, 21618 => 21017, 21619 => 27901, 21620 => 36156, - 21621 => 24590, 21622 => 22686, 21623 => 24974, 21624 => 26366, 21625 => 36192, - 21626 => 25166, 21627 => 21939, 21628 => 28195, 21629 => 26413, 21630 => 36711, - 21793 => 38113, 21794 => 38392, 21795 => 30504, 21796 => 26629, 21797 => 27048, - 21798 => 21643, 21799 => 20045, 21800 => 28856, 21801 => 35784, 21802 => 25688, - 21803 => 25995, 21804 => 23429, 21805 => 31364, 21806 => 20538, 21807 => 23528, - 21808 => 30651, 21809 => 27617, 21810 => 35449, 21811 => 31896, 21812 => 27838, - 21813 => 30415, 21814 => 26025, 21815 => 36759, 21816 => 23853, 21817 => 23637, - 21818 => 34360, 21819 => 26632, 21820 => 21344, 21821 => 25112, 21822 => 31449, - 21823 => 28251, 21824 => 32509, 21825 => 27167, 21826 => 31456, 21827 => 24432, - 21828 => 28467, 21829 => 24352, 21830 => 25484, 21831 => 28072, 21832 => 26454, - 21833 => 19976, 21834 => 24080, 21835 => 36134, 21836 => 20183, 21837 => 32960, - 21838 => 30260, 21839 => 38556, 21840 => 25307, 21841 => 26157, 21842 => 25214, - 21843 => 27836, 21844 => 36213, 21845 => 29031, 21846 => 32617, 21847 => 20806, - 21848 => 32903, 21849 => 21484, 21850 => 36974, 21851 => 25240, 21852 => 21746, - 21853 => 34544, 21854 => 36761, 21855 => 32773, 21856 => 38167, 21857 => 34071, - 21858 => 36825, 21859 => 27993, 21860 => 29645, 21861 => 26015, 21862 => 30495, - 21863 => 29956, 21864 => 30759, 21865 => 33275, 21866 => 36126, 21867 => 38024, - 21868 => 20390, 21869 => 26517, 21870 => 30137, 21871 => 35786, 21872 => 38663, - 21873 => 25391, 21874 => 38215, 21875 => 38453, 21876 => 33976, 21877 => 25379, - 21878 => 30529, 21879 => 24449, 21880 => 29424, 21881 => 20105, 21882 => 24596, - 21883 => 25972, 21884 => 25327, 21885 => 27491, 21886 => 25919, 22049 => 24103, - 22050 => 30151, 22051 => 37073, 22052 => 35777, 22053 => 33437, 22054 => 26525, - 22055 => 25903, 22056 => 21553, 22057 => 34584, 22058 => 30693, 22059 => 32930, - 22060 => 33026, 22061 => 27713, 22062 => 20043, 22063 => 32455, 22064 => 32844, - 22065 => 30452, 22066 => 26893, 22067 => 27542, 22068 => 25191, 22069 => 20540, - 22070 => 20356, 22071 => 22336, 22072 => 25351, 22073 => 27490, 22074 => 36286, - 22075 => 21482, 22076 => 26088, 22077 => 32440, 22078 => 24535, 22079 => 25370, - 22080 => 25527, 22081 => 33267, 22082 => 33268, 22083 => 32622, 22084 => 24092, - 22085 => 23769, 22086 => 21046, 22087 => 26234, 22088 => 31209, 22089 => 31258, - 22090 => 36136, 22091 => 28825, 22092 => 30164, 22093 => 28382, 22094 => 27835, - 22095 => 31378, 22096 => 20013, 22097 => 30405, 22098 => 24544, 22099 => 38047, - 22100 => 34935, 22101 => 32456, 22102 => 31181, 22103 => 32959, 22104 => 37325, - 22105 => 20210, 22106 => 20247, 22107 => 33311, 22108 => 21608, 22109 => 24030, - 22110 => 27954, 22111 => 35788, 22112 => 31909, 22113 => 36724, 22114 => 32920, - 22115 => 24090, 22116 => 21650, 22117 => 30385, 22118 => 23449, 22119 => 26172, - 22120 => 39588, 22121 => 29664, 22122 => 26666, 22123 => 34523, 22124 => 26417, - 22125 => 29482, 22126 => 35832, 22127 => 35803, 22128 => 36880, 22129 => 31481, - 22130 => 28891, 22131 => 29038, 22132 => 25284, 22133 => 30633, 22134 => 22065, - 22135 => 20027, 22136 => 33879, 22137 => 26609, 22138 => 21161, 22139 => 34496, - 22140 => 36142, 22141 => 38136, 22142 => 31569, 22305 => 20303, 22306 => 27880, - 22307 => 31069, 22308 => 39547, 22309 => 25235, 22310 => 29226, 22311 => 25341, - 22312 => 19987, 22313 => 30742, 22314 => 36716, 22315 => 25776, 22316 => 36186, - 22317 => 31686, 22318 => 26729, 22319 => 24196, 22320 => 35013, 22321 => 22918, - 22322 => 25758, 22323 => 22766, 22324 => 29366, 22325 => 26894, 22326 => 38181, - 22327 => 36861, 22328 => 36184, 22329 => 22368, 22330 => 32512, 22331 => 35846, - 22332 => 20934, 22333 => 25417, 22334 => 25305, 22335 => 21331, 22336 => 26700, - 22337 => 29730, 22338 => 33537, 22339 => 37196, 22340 => 21828, 22341 => 30528, - 22342 => 28796, 22343 => 27978, 22344 => 20857, 22345 => 21672, 22346 => 36164, - 22347 => 23039, 22348 => 28363, 22349 => 28100, 22350 => 23388, 22351 => 32043, - 22352 => 20180, 22353 => 31869, 22354 => 28371, 22355 => 23376, 22356 => 33258, - 22357 => 28173, 22358 => 23383, 22359 => 39683, 22360 => 26837, 22361 => 36394, - 22362 => 23447, 22363 => 32508, 22364 => 24635, 22365 => 32437, 22366 => 37049, - 22367 => 36208, 22368 => 22863, 22369 => 25549, 22370 => 31199, 22371 => 36275, - 22372 => 21330, 22373 => 26063, 22374 => 31062, 22375 => 35781, 22376 => 38459, - 22377 => 32452, 22378 => 38075, 22379 => 32386, 22380 => 22068, 22381 => 37257, - 22382 => 26368, 22383 => 32618, 22384 => 23562, 22385 => 36981, 22386 => 26152, - 22387 => 24038, 22388 => 20304, 22389 => 26590, 22390 => 20570, 22391 => 20316, - 22392 => 22352, 22393 => 24231, 22561 => 20109, 22562 => 19980, 22563 => 20800, - 22564 => 19984, 22565 => 24319, 22566 => 21317, 22567 => 19989, 22568 => 20120, - 22569 => 19998, 22570 => 39730, 22571 => 23404, 22572 => 22121, 22573 => 20008, - 22574 => 31162, 22575 => 20031, 22576 => 21269, 22577 => 20039, 22578 => 22829, - 22579 => 29243, 22580 => 21358, 22581 => 27664, 22582 => 22239, 22583 => 32996, - 22584 => 39319, 22585 => 27603, 22586 => 30590, 22587 => 40727, 22588 => 20022, - 22589 => 20127, 22590 => 40720, 22591 => 20060, 22592 => 20073, 22593 => 20115, - 22594 => 33416, 22595 => 23387, 22596 => 21868, 22597 => 22031, 22598 => 20164, - 22599 => 21389, 22600 => 21405, 22601 => 21411, 22602 => 21413, 22603 => 21422, - 22604 => 38757, 22605 => 36189, 22606 => 21274, 22607 => 21493, 22608 => 21286, - 22609 => 21294, 22610 => 21310, 22611 => 36188, 22612 => 21350, 22613 => 21347, - 22614 => 20994, 22615 => 21000, 22616 => 21006, 22617 => 21037, 22618 => 21043, - 22619 => 21055, 22620 => 21056, 22621 => 21068, 22622 => 21086, 22623 => 21089, - 22624 => 21084, 22625 => 33967, 22626 => 21117, 22627 => 21122, 22628 => 21121, - 22629 => 21136, 22630 => 21139, 22631 => 20866, 22632 => 32596, 22633 => 20155, - 22634 => 20163, 22635 => 20169, 22636 => 20162, 22637 => 20200, 22638 => 20193, - 22639 => 20203, 22640 => 20190, 22641 => 20251, 22642 => 20211, 22643 => 20258, - 22644 => 20324, 22645 => 20213, 22646 => 20261, 22647 => 20263, 22648 => 20233, - 22649 => 20267, 22650 => 20318, 22651 => 20327, 22652 => 25912, 22653 => 20314, - 22654 => 20317, 22817 => 20319, 22818 => 20311, 22819 => 20274, 22820 => 20285, - 22821 => 20342, 22822 => 20340, 22823 => 20369, 22824 => 20361, 22825 => 20355, - 22826 => 20367, 22827 => 20350, 22828 => 20347, 22829 => 20394, 22830 => 20348, - 22831 => 20396, 22832 => 20372, 22833 => 20454, 22834 => 20456, 22835 => 20458, - 22836 => 20421, 22837 => 20442, 22838 => 20451, 22839 => 20444, 22840 => 20433, - 22841 => 20447, 22842 => 20472, 22843 => 20521, 22844 => 20556, 22845 => 20467, - 22846 => 20524, 22847 => 20495, 22848 => 20526, 22849 => 20525, 22850 => 20478, - 22851 => 20508, 22852 => 20492, 22853 => 20517, 22854 => 20520, 22855 => 20606, - 22856 => 20547, 22857 => 20565, 22858 => 20552, 22859 => 20558, 22860 => 20588, - 22861 => 20603, 22862 => 20645, 22863 => 20647, 22864 => 20649, 22865 => 20666, - 22866 => 20694, 22867 => 20742, 22868 => 20717, 22869 => 20716, 22870 => 20710, - 22871 => 20718, 22872 => 20743, 22873 => 20747, 22874 => 20189, 22875 => 27709, - 22876 => 20312, 22877 => 20325, 22878 => 20430, 22879 => 40864, 22880 => 27718, - 22881 => 31860, 22882 => 20846, 22883 => 24061, 22884 => 40649, 22885 => 39320, - 22886 => 20865, 22887 => 22804, 22888 => 21241, 22889 => 21261, 22890 => 35335, - 22891 => 21264, 22892 => 20971, 22893 => 22809, 22894 => 20821, 22895 => 20128, - 22896 => 20822, 22897 => 20147, 22898 => 34926, 22899 => 34980, 22900 => 20149, - 22901 => 33044, 22902 => 35026, 22903 => 31104, 22904 => 23348, 22905 => 34819, - 22906 => 32696, 22907 => 20907, 22908 => 20913, 22909 => 20925, 22910 => 20924, - 23073 => 20935, 23074 => 20886, 23075 => 20898, 23076 => 20901, 23077 => 35744, - 23078 => 35750, 23079 => 35751, 23080 => 35754, 23081 => 35764, 23082 => 35765, - 23083 => 35767, 23084 => 35778, 23085 => 35779, 23086 => 35787, 23087 => 35791, - 23088 => 35790, 23089 => 35794, 23090 => 35795, 23091 => 35796, 23092 => 35798, - 23093 => 35800, 23094 => 35801, 23095 => 35804, 23096 => 35807, 23097 => 35808, - 23098 => 35812, 23099 => 35816, 23100 => 35817, 23101 => 35822, 23102 => 35824, - 23103 => 35827, 23104 => 35830, 23105 => 35833, 23106 => 35836, 23107 => 35839, - 23108 => 35840, 23109 => 35842, 23110 => 35844, 23111 => 35847, 23112 => 35852, - 23113 => 35855, 23114 => 35857, 23115 => 35858, 23116 => 35860, 23117 => 35861, - 23118 => 35862, 23119 => 35865, 23120 => 35867, 23121 => 35864, 23122 => 35869, - 23123 => 35871, 23124 => 35872, 23125 => 35873, 23126 => 35877, 23127 => 35879, - 23128 => 35882, 23129 => 35883, 23130 => 35886, 23131 => 35887, 23132 => 35890, - 23133 => 35891, 23134 => 35893, 23135 => 35894, 23136 => 21353, 23137 => 21370, - 23138 => 38429, 23139 => 38434, 23140 => 38433, 23141 => 38449, 23142 => 38442, - 23143 => 38461, 23144 => 38460, 23145 => 38466, 23146 => 38473, 23147 => 38484, - 23148 => 38495, 23149 => 38503, 23150 => 38508, 23151 => 38514, 23152 => 38516, - 23153 => 38536, 23154 => 38541, 23155 => 38551, 23156 => 38576, 23157 => 37015, - 23158 => 37019, 23159 => 37021, 23160 => 37017, 23161 => 37036, 23162 => 37025, - 23163 => 37044, 23164 => 37043, 23165 => 37046, 23166 => 37050, 23329 => 37048, - 23330 => 37040, 23331 => 37071, 23332 => 37061, 23333 => 37054, 23334 => 37072, - 23335 => 37060, 23336 => 37063, 23337 => 37075, 23338 => 37094, 23339 => 37090, - 23340 => 37084, 23341 => 37079, 23342 => 37083, 23343 => 37099, 23344 => 37103, - 23345 => 37118, 23346 => 37124, 23347 => 37154, 23348 => 37150, 23349 => 37155, - 23350 => 37169, 23351 => 37167, 23352 => 37177, 23353 => 37187, 23354 => 37190, - 23355 => 21005, 23356 => 22850, 23357 => 21154, 23358 => 21164, 23359 => 21165, - 23360 => 21182, 23361 => 21759, 23362 => 21200, 23363 => 21206, 23364 => 21232, - 23365 => 21471, 23366 => 29166, 23367 => 30669, 23368 => 24308, 23369 => 20981, - 23370 => 20988, 23371 => 39727, 23372 => 21430, 23373 => 24321, 23374 => 30042, - 23375 => 24047, 23376 => 22348, 23377 => 22441, 23378 => 22433, 23379 => 22654, - 23380 => 22716, 23381 => 22725, 23382 => 22737, 23383 => 22313, 23384 => 22316, - 23385 => 22314, 23386 => 22323, 23387 => 22329, 23388 => 22318, 23389 => 22319, - 23390 => 22364, 23391 => 22331, 23392 => 22338, 23393 => 22377, 23394 => 22405, - 23395 => 22379, 23396 => 22406, 23397 => 22396, 23398 => 22395, 23399 => 22376, - 23400 => 22381, 23401 => 22390, 23402 => 22387, 23403 => 22445, 23404 => 22436, - 23405 => 22412, 23406 => 22450, 23407 => 22479, 23408 => 22439, 23409 => 22452, - 23410 => 22419, 23411 => 22432, 23412 => 22485, 23413 => 22488, 23414 => 22490, - 23415 => 22489, 23416 => 22482, 23417 => 22456, 23418 => 22516, 23419 => 22511, - 23420 => 22520, 23421 => 22500, 23422 => 22493, 23585 => 22539, 23586 => 22541, - 23587 => 22525, 23588 => 22509, 23589 => 22528, 23590 => 22558, 23591 => 22553, - 23592 => 22596, 23593 => 22560, 23594 => 22629, 23595 => 22636, 23596 => 22657, - 23597 => 22665, 23598 => 22682, 23599 => 22656, 23600 => 39336, 23601 => 40729, - 23602 => 25087, 23603 => 33401, 23604 => 33405, 23605 => 33407, 23606 => 33423, - 23607 => 33418, 23608 => 33448, 23609 => 33412, 23610 => 33422, 23611 => 33425, - 23612 => 33431, 23613 => 33433, 23614 => 33451, 23615 => 33464, 23616 => 33470, - 23617 => 33456, 23618 => 33480, 23619 => 33482, 23620 => 33507, 23621 => 33432, - 23622 => 33463, 23623 => 33454, 23624 => 33483, 23625 => 33484, 23626 => 33473, - 23627 => 33449, 23628 => 33460, 23629 => 33441, 23630 => 33450, 23631 => 33439, - 23632 => 33476, 23633 => 33486, 23634 => 33444, 23635 => 33505, 23636 => 33545, - 23637 => 33527, 23638 => 33508, 23639 => 33551, 23640 => 33543, 23641 => 33500, - 23642 => 33524, 23643 => 33490, 23644 => 33496, 23645 => 33548, 23646 => 33531, - 23647 => 33491, 23648 => 33553, 23649 => 33562, 23650 => 33542, 23651 => 33556, - 23652 => 33557, 23653 => 33504, 23654 => 33493, 23655 => 33564, 23656 => 33617, - 23657 => 33627, 23658 => 33628, 23659 => 33544, 23660 => 33682, 23661 => 33596, - 23662 => 33588, 23663 => 33585, 23664 => 33691, 23665 => 33630, 23666 => 33583, - 23667 => 33615, 23668 => 33607, 23669 => 33603, 23670 => 33631, 23671 => 33600, - 23672 => 33559, 23673 => 33632, 23674 => 33581, 23675 => 33594, 23676 => 33587, - 23677 => 33638, 23678 => 33637, 23841 => 33640, 23842 => 33563, 23843 => 33641, - 23844 => 33644, 23845 => 33642, 23846 => 33645, 23847 => 33646, 23848 => 33712, - 23849 => 33656, 23850 => 33715, 23851 => 33716, 23852 => 33696, 23853 => 33706, - 23854 => 33683, 23855 => 33692, 23856 => 33669, 23857 => 33660, 23858 => 33718, - 23859 => 33705, 23860 => 33661, 23861 => 33720, 23862 => 33659, 23863 => 33688, - 23864 => 33694, 23865 => 33704, 23866 => 33722, 23867 => 33724, 23868 => 33729, - 23869 => 33793, 23870 => 33765, 23871 => 33752, 23872 => 22535, 23873 => 33816, - 23874 => 33803, 23875 => 33757, 23876 => 33789, 23877 => 33750, 23878 => 33820, - 23879 => 33848, 23880 => 33809, 23881 => 33798, 23882 => 33748, 23883 => 33759, - 23884 => 33807, 23885 => 33795, 23886 => 33784, 23887 => 33785, 23888 => 33770, - 23889 => 33733, 23890 => 33728, 23891 => 33830, 23892 => 33776, 23893 => 33761, - 23894 => 33884, 23895 => 33873, 23896 => 33882, 23897 => 33881, 23898 => 33907, - 23899 => 33927, 23900 => 33928, 23901 => 33914, 23902 => 33929, 23903 => 33912, - 23904 => 33852, 23905 => 33862, 23906 => 33897, 23907 => 33910, 23908 => 33932, - 23909 => 33934, 23910 => 33841, 23911 => 33901, 23912 => 33985, 23913 => 33997, - 23914 => 34000, 23915 => 34022, 23916 => 33981, 23917 => 34003, 23918 => 33994, - 23919 => 33983, 23920 => 33978, 23921 => 34016, 23922 => 33953, 23923 => 33977, - 23924 => 33972, 23925 => 33943, 23926 => 34021, 23927 => 34019, 23928 => 34060, - 23929 => 29965, 23930 => 34104, 23931 => 34032, 23932 => 34105, 23933 => 34079, - 23934 => 34106, 24097 => 34134, 24098 => 34107, 24099 => 34047, 24100 => 34044, - 24101 => 34137, 24102 => 34120, 24103 => 34152, 24104 => 34148, 24105 => 34142, - 24106 => 34170, 24107 => 30626, 24108 => 34115, 24109 => 34162, 24110 => 34171, - 24111 => 34212, 24112 => 34216, 24113 => 34183, 24114 => 34191, 24115 => 34169, - 24116 => 34222, 24117 => 34204, 24118 => 34181, 24119 => 34233, 24120 => 34231, - 24121 => 34224, 24122 => 34259, 24123 => 34241, 24124 => 34268, 24125 => 34303, - 24126 => 34343, 24127 => 34309, 24128 => 34345, 24129 => 34326, 24130 => 34364, - 24131 => 24318, 24132 => 24328, 24133 => 22844, 24134 => 22849, 24135 => 32823, - 24136 => 22869, 24137 => 22874, 24138 => 22872, 24139 => 21263, 24140 => 23586, - 24141 => 23589, 24142 => 23596, 24143 => 23604, 24144 => 25164, 24145 => 25194, - 24146 => 25247, 24147 => 25275, 24148 => 25290, 24149 => 25306, 24150 => 25303, - 24151 => 25326, 24152 => 25378, 24153 => 25334, 24154 => 25401, 24155 => 25419, - 24156 => 25411, 24157 => 25517, 24158 => 25590, 24159 => 25457, 24160 => 25466, - 24161 => 25486, 24162 => 25524, 24163 => 25453, 24164 => 25516, 24165 => 25482, - 24166 => 25449, 24167 => 25518, 24168 => 25532, 24169 => 25586, 24170 => 25592, - 24171 => 25568, 24172 => 25599, 24173 => 25540, 24174 => 25566, 24175 => 25550, - 24176 => 25682, 24177 => 25542, 24178 => 25534, 24179 => 25669, 24180 => 25665, - 24181 => 25611, 24182 => 25627, 24183 => 25632, 24184 => 25612, 24185 => 25638, - 24186 => 25633, 24187 => 25694, 24188 => 25732, 24189 => 25709, 24190 => 25750, - 24353 => 25722, 24354 => 25783, 24355 => 25784, 24356 => 25753, 24357 => 25786, - 24358 => 25792, 24359 => 25808, 24360 => 25815, 24361 => 25828, 24362 => 25826, - 24363 => 25865, 24364 => 25893, 24365 => 25902, 24366 => 24331, 24367 => 24530, - 24368 => 29977, 24369 => 24337, 24370 => 21343, 24371 => 21489, 24372 => 21501, - 24373 => 21481, 24374 => 21480, 24375 => 21499, 24376 => 21522, 24377 => 21526, - 24378 => 21510, 24379 => 21579, 24380 => 21586, 24381 => 21587, 24382 => 21588, - 24383 => 21590, 24384 => 21571, 24385 => 21537, 24386 => 21591, 24387 => 21593, - 24388 => 21539, 24389 => 21554, 24390 => 21634, 24391 => 21652, 24392 => 21623, - 24393 => 21617, 24394 => 21604, 24395 => 21658, 24396 => 21659, 24397 => 21636, - 24398 => 21622, 24399 => 21606, 24400 => 21661, 24401 => 21712, 24402 => 21677, - 24403 => 21698, 24404 => 21684, 24405 => 21714, 24406 => 21671, 24407 => 21670, - 24408 => 21715, 24409 => 21716, 24410 => 21618, 24411 => 21667, 24412 => 21717, - 24413 => 21691, 24414 => 21695, 24415 => 21708, 24416 => 21721, 24417 => 21722, - 24418 => 21724, 24419 => 21673, 24420 => 21674, 24421 => 21668, 24422 => 21725, - 24423 => 21711, 24424 => 21726, 24425 => 21787, 24426 => 21735, 24427 => 21792, - 24428 => 21757, 24429 => 21780, 24430 => 21747, 24431 => 21794, 24432 => 21795, - 24433 => 21775, 24434 => 21777, 24435 => 21799, 24436 => 21802, 24437 => 21863, - 24438 => 21903, 24439 => 21941, 24440 => 21833, 24441 => 21869, 24442 => 21825, - 24443 => 21845, 24444 => 21823, 24445 => 21840, 24446 => 21820, 24609 => 21815, - 24610 => 21846, 24611 => 21877, 24612 => 21878, 24613 => 21879, 24614 => 21811, - 24615 => 21808, 24616 => 21852, 24617 => 21899, 24618 => 21970, 24619 => 21891, - 24620 => 21937, 24621 => 21945, 24622 => 21896, 24623 => 21889, 24624 => 21919, - 24625 => 21886, 24626 => 21974, 24627 => 21905, 24628 => 21883, 24629 => 21983, - 24630 => 21949, 24631 => 21950, 24632 => 21908, 24633 => 21913, 24634 => 21994, - 24635 => 22007, 24636 => 21961, 24637 => 22047, 24638 => 21969, 24639 => 21995, - 24640 => 21996, 24641 => 21972, 24642 => 21990, 24643 => 21981, 24644 => 21956, - 24645 => 21999, 24646 => 21989, 24647 => 22002, 24648 => 22003, 24649 => 21964, - 24650 => 21965, 24651 => 21992, 24652 => 22005, 24653 => 21988, 24654 => 36756, - 24655 => 22046, 24656 => 22024, 24657 => 22028, 24658 => 22017, 24659 => 22052, - 24660 => 22051, 24661 => 22014, 24662 => 22016, 24663 => 22055, 24664 => 22061, - 24665 => 22104, 24666 => 22073, 24667 => 22103, 24668 => 22060, 24669 => 22093, - 24670 => 22114, 24671 => 22105, 24672 => 22108, 24673 => 22092, 24674 => 22100, - 24675 => 22150, 24676 => 22116, 24677 => 22129, 24678 => 22123, 24679 => 22139, - 24680 => 22140, 24681 => 22149, 24682 => 22163, 24683 => 22191, 24684 => 22228, - 24685 => 22231, 24686 => 22237, 24687 => 22241, 24688 => 22261, 24689 => 22251, - 24690 => 22265, 24691 => 22271, 24692 => 22276, 24693 => 22282, 24694 => 22281, - 24695 => 22300, 24696 => 24079, 24697 => 24089, 24698 => 24084, 24699 => 24081, - 24700 => 24113, 24701 => 24123, 24702 => 24124, 24865 => 24119, 24866 => 24132, - 24867 => 24148, 24868 => 24155, 24869 => 24158, 24870 => 24161, 24871 => 23692, - 24872 => 23674, 24873 => 23693, 24874 => 23696, 24875 => 23702, 24876 => 23688, - 24877 => 23704, 24878 => 23705, 24879 => 23697, 24880 => 23706, 24881 => 23708, - 24882 => 23733, 24883 => 23714, 24884 => 23741, 24885 => 23724, 24886 => 23723, - 24887 => 23729, 24888 => 23715, 24889 => 23745, 24890 => 23735, 24891 => 23748, - 24892 => 23762, 24893 => 23780, 24894 => 23755, 24895 => 23781, 24896 => 23810, - 24897 => 23811, 24898 => 23847, 24899 => 23846, 24900 => 23854, 24901 => 23844, - 24902 => 23838, 24903 => 23814, 24904 => 23835, 24905 => 23896, 24906 => 23870, - 24907 => 23860, 24908 => 23869, 24909 => 23916, 24910 => 23899, 24911 => 23919, - 24912 => 23901, 24913 => 23915, 24914 => 23883, 24915 => 23882, 24916 => 23913, - 24917 => 23924, 24918 => 23938, 24919 => 23961, 24920 => 23965, 24921 => 35955, - 24922 => 23991, 24923 => 24005, 24924 => 24435, 24925 => 24439, 24926 => 24450, - 24927 => 24455, 24928 => 24457, 24929 => 24460, 24930 => 24469, 24931 => 24473, - 24932 => 24476, 24933 => 24488, 24934 => 24493, 24935 => 24501, 24936 => 24508, - 24937 => 34914, 24938 => 24417, 24939 => 29357, 24940 => 29360, 24941 => 29364, - 24942 => 29367, 24943 => 29368, 24944 => 29379, 24945 => 29377, 24946 => 29390, - 24947 => 29389, 24948 => 29394, 24949 => 29416, 24950 => 29423, 24951 => 29417, - 24952 => 29426, 24953 => 29428, 24954 => 29431, 24955 => 29441, 24956 => 29427, - 24957 => 29443, 24958 => 29434, 25121 => 29435, 25122 => 29463, 25123 => 29459, - 25124 => 29473, 25125 => 29450, 25126 => 29470, 25127 => 29469, 25128 => 29461, - 25129 => 29474, 25130 => 29497, 25131 => 29477, 25132 => 29484, 25133 => 29496, - 25134 => 29489, 25135 => 29520, 25136 => 29517, 25137 => 29527, 25138 => 29536, - 25139 => 29548, 25140 => 29551, 25141 => 29566, 25142 => 33307, 25143 => 22821, - 25144 => 39143, 25145 => 22820, 25146 => 22786, 25147 => 39267, 25148 => 39271, - 25149 => 39272, 25150 => 39273, 25151 => 39274, 25152 => 39275, 25153 => 39276, - 25154 => 39284, 25155 => 39287, 25156 => 39293, 25157 => 39296, 25158 => 39300, - 25159 => 39303, 25160 => 39306, 25161 => 39309, 25162 => 39312, 25163 => 39313, - 25164 => 39315, 25165 => 39316, 25166 => 39317, 25167 => 24192, 25168 => 24209, - 25169 => 24203, 25170 => 24214, 25171 => 24229, 25172 => 24224, 25173 => 24249, - 25174 => 24245, 25175 => 24254, 25176 => 24243, 25177 => 36179, 25178 => 24274, - 25179 => 24273, 25180 => 24283, 25181 => 24296, 25182 => 24298, 25183 => 33210, - 25184 => 24516, 25185 => 24521, 25186 => 24534, 25187 => 24527, 25188 => 24579, - 25189 => 24558, 25190 => 24580, 25191 => 24545, 25192 => 24548, 25193 => 24574, - 25194 => 24581, 25195 => 24582, 25196 => 24554, 25197 => 24557, 25198 => 24568, - 25199 => 24601, 25200 => 24629, 25201 => 24614, 25202 => 24603, 25203 => 24591, - 25204 => 24589, 25205 => 24617, 25206 => 24619, 25207 => 24586, 25208 => 24639, - 25209 => 24609, 25210 => 24696, 25211 => 24697, 25212 => 24699, 25213 => 24698, - 25214 => 24642, 25377 => 24682, 25378 => 24701, 25379 => 24726, 25380 => 24730, - 25381 => 24749, 25382 => 24733, 25383 => 24707, 25384 => 24722, 25385 => 24716, - 25386 => 24731, 25387 => 24812, 25388 => 24763, 25389 => 24753, 25390 => 24797, - 25391 => 24792, 25392 => 24774, 25393 => 24794, 25394 => 24756, 25395 => 24864, - 25396 => 24870, 25397 => 24853, 25398 => 24867, 25399 => 24820, 25400 => 24832, - 25401 => 24846, 25402 => 24875, 25403 => 24906, 25404 => 24949, 25405 => 25004, - 25406 => 24980, 25407 => 24999, 25408 => 25015, 25409 => 25044, 25410 => 25077, - 25411 => 24541, 25412 => 38579, 25413 => 38377, 25414 => 38379, 25415 => 38385, - 25416 => 38387, 25417 => 38389, 25418 => 38390, 25419 => 38396, 25420 => 38398, - 25421 => 38403, 25422 => 38404, 25423 => 38406, 25424 => 38408, 25425 => 38410, - 25426 => 38411, 25427 => 38412, 25428 => 38413, 25429 => 38415, 25430 => 38418, - 25431 => 38421, 25432 => 38422, 25433 => 38423, 25434 => 38425, 25435 => 38426, - 25436 => 20012, 25437 => 29247, 25438 => 25109, 25439 => 27701, 25440 => 27732, - 25441 => 27740, 25442 => 27722, 25443 => 27811, 25444 => 27781, 25445 => 27792, - 25446 => 27796, 25447 => 27788, 25448 => 27752, 25449 => 27753, 25450 => 27764, - 25451 => 27766, 25452 => 27782, 25453 => 27817, 25454 => 27856, 25455 => 27860, - 25456 => 27821, 25457 => 27895, 25458 => 27896, 25459 => 27889, 25460 => 27863, - 25461 => 27826, 25462 => 27872, 25463 => 27862, 25464 => 27898, 25465 => 27883, - 25466 => 27886, 25467 => 27825, 25468 => 27859, 25469 => 27887, 25470 => 27902, - 25633 => 27961, 25634 => 27943, 25635 => 27916, 25636 => 27971, 25637 => 27976, - 25638 => 27911, 25639 => 27908, 25640 => 27929, 25641 => 27918, 25642 => 27947, - 25643 => 27981, 25644 => 27950, 25645 => 27957, 25646 => 27930, 25647 => 27983, - 25648 => 27986, 25649 => 27988, 25650 => 27955, 25651 => 28049, 25652 => 28015, - 25653 => 28062, 25654 => 28064, 25655 => 27998, 25656 => 28051, 25657 => 28052, - 25658 => 27996, 25659 => 28000, 25660 => 28028, 25661 => 28003, 25662 => 28186, - 25663 => 28103, 25664 => 28101, 25665 => 28126, 25666 => 28174, 25667 => 28095, - 25668 => 28128, 25669 => 28177, 25670 => 28134, 25671 => 28125, 25672 => 28121, - 25673 => 28182, 25674 => 28075, 25675 => 28172, 25676 => 28078, 25677 => 28203, - 25678 => 28270, 25679 => 28238, 25680 => 28267, 25681 => 28338, 25682 => 28255, - 25683 => 28294, 25684 => 28243, 25685 => 28244, 25686 => 28210, 25687 => 28197, - 25688 => 28228, 25689 => 28383, 25690 => 28337, 25691 => 28312, 25692 => 28384, - 25693 => 28461, 25694 => 28386, 25695 => 28325, 25696 => 28327, 25697 => 28349, - 25698 => 28347, 25699 => 28343, 25700 => 28375, 25701 => 28340, 25702 => 28367, - 25703 => 28303, 25704 => 28354, 25705 => 28319, 25706 => 28514, 25707 => 28486, - 25708 => 28487, 25709 => 28452, 25710 => 28437, 25711 => 28409, 25712 => 28463, - 25713 => 28470, 25714 => 28491, 25715 => 28532, 25716 => 28458, 25717 => 28425, - 25718 => 28457, 25719 => 28553, 25720 => 28557, 25721 => 28556, 25722 => 28536, - 25723 => 28530, 25724 => 28540, 25725 => 28538, 25726 => 28625, 25889 => 28617, - 25890 => 28583, 25891 => 28601, 25892 => 28598, 25893 => 28610, 25894 => 28641, - 25895 => 28654, 25896 => 28638, 25897 => 28640, 25898 => 28655, 25899 => 28698, - 25900 => 28707, 25901 => 28699, 25902 => 28729, 25903 => 28725, 25904 => 28751, - 25905 => 28766, 25906 => 23424, 25907 => 23428, 25908 => 23445, 25909 => 23443, - 25910 => 23461, 25911 => 23480, 25912 => 29999, 25913 => 39582, 25914 => 25652, - 25915 => 23524, 25916 => 23534, 25917 => 35120, 25918 => 23536, 25919 => 36423, - 25920 => 35591, 25921 => 36790, 25922 => 36819, 25923 => 36821, 25924 => 36837, - 25925 => 36846, 25926 => 36836, 25927 => 36841, 25928 => 36838, 25929 => 36851, - 25930 => 36840, 25931 => 36869, 25932 => 36868, 25933 => 36875, 25934 => 36902, - 25935 => 36881, 25936 => 36877, 25937 => 36886, 25938 => 36897, 25939 => 36917, - 25940 => 36918, 25941 => 36909, 25942 => 36911, 25943 => 36932, 25944 => 36945, - 25945 => 36946, 25946 => 36944, 25947 => 36968, 25948 => 36952, 25949 => 36962, - 25950 => 36955, 25951 => 26297, 25952 => 36980, 25953 => 36989, 25954 => 36994, - 25955 => 37000, 25956 => 36995, 25957 => 37003, 25958 => 24400, 25959 => 24407, - 25960 => 24406, 25961 => 24408, 25962 => 23611, 25963 => 21675, 25964 => 23632, - 25965 => 23641, 25966 => 23409, 25967 => 23651, 25968 => 23654, 25969 => 32700, - 25970 => 24362, 25971 => 24361, 25972 => 24365, 25973 => 33396, 25974 => 24380, - 25975 => 39739, 25976 => 23662, 25977 => 22913, 25978 => 22915, 25979 => 22925, - 25980 => 22953, 25981 => 22954, 25982 => 22947, 26145 => 22935, 26146 => 22986, - 26147 => 22955, 26148 => 22942, 26149 => 22948, 26150 => 22994, 26151 => 22962, - 26152 => 22959, 26153 => 22999, 26154 => 22974, 26155 => 23045, 26156 => 23046, - 26157 => 23005, 26158 => 23048, 26159 => 23011, 26160 => 23000, 26161 => 23033, - 26162 => 23052, 26163 => 23049, 26164 => 23090, 26165 => 23092, 26166 => 23057, - 26167 => 23075, 26168 => 23059, 26169 => 23104, 26170 => 23143, 26171 => 23114, - 26172 => 23125, 26173 => 23100, 26174 => 23138, 26175 => 23157, 26176 => 33004, - 26177 => 23210, 26178 => 23195, 26179 => 23159, 26180 => 23162, 26181 => 23230, - 26182 => 23275, 26183 => 23218, 26184 => 23250, 26185 => 23252, 26186 => 23224, - 26187 => 23264, 26188 => 23267, 26189 => 23281, 26190 => 23254, 26191 => 23270, - 26192 => 23256, 26193 => 23260, 26194 => 23305, 26195 => 23319, 26196 => 23318, - 26197 => 23346, 26198 => 23351, 26199 => 23360, 26200 => 23573, 26201 => 23580, - 26202 => 23386, 26203 => 23397, 26204 => 23411, 26205 => 23377, 26206 => 23379, - 26207 => 23394, 26208 => 39541, 26209 => 39543, 26210 => 39544, 26211 => 39546, - 26212 => 39551, 26213 => 39549, 26214 => 39552, 26215 => 39553, 26216 => 39557, - 26217 => 39560, 26218 => 39562, 26219 => 39568, 26220 => 39570, 26221 => 39571, - 26222 => 39574, 26223 => 39576, 26224 => 39579, 26225 => 39580, 26226 => 39581, - 26227 => 39583, 26228 => 39584, 26229 => 39586, 26230 => 39587, 26231 => 39589, - 26232 => 39591, 26233 => 32415, 26234 => 32417, 26235 => 32419, 26236 => 32421, - 26237 => 32424, 26238 => 32425, 26401 => 32429, 26402 => 32432, 26403 => 32446, - 26404 => 32448, 26405 => 32449, 26406 => 32450, 26407 => 32457, 26408 => 32459, - 26409 => 32460, 26410 => 32464, 26411 => 32468, 26412 => 32471, 26413 => 32475, - 26414 => 32480, 26415 => 32481, 26416 => 32488, 26417 => 32491, 26418 => 32494, - 26419 => 32495, 26420 => 32497, 26421 => 32498, 26422 => 32525, 26423 => 32502, - 26424 => 32506, 26425 => 32507, 26426 => 32510, 26427 => 32513, 26428 => 32514, - 26429 => 32515, 26430 => 32519, 26431 => 32520, 26432 => 32523, 26433 => 32524, - 26434 => 32527, 26435 => 32529, 26436 => 32530, 26437 => 32535, 26438 => 32537, - 26439 => 32540, 26440 => 32539, 26441 => 32543, 26442 => 32545, 26443 => 32546, - 26444 => 32547, 26445 => 32548, 26446 => 32549, 26447 => 32550, 26448 => 32551, - 26449 => 32554, 26450 => 32555, 26451 => 32556, 26452 => 32557, 26453 => 32559, - 26454 => 32560, 26455 => 32561, 26456 => 32562, 26457 => 32563, 26458 => 32565, - 26459 => 24186, 26460 => 30079, 26461 => 24027, 26462 => 30014, 26463 => 37013, - 26464 => 29582, 26465 => 29585, 26466 => 29614, 26467 => 29602, 26468 => 29599, - 26469 => 29647, 26470 => 29634, 26471 => 29649, 26472 => 29623, 26473 => 29619, - 26474 => 29632, 26475 => 29641, 26476 => 29640, 26477 => 29669, 26478 => 29657, - 26479 => 39036, 26480 => 29706, 26481 => 29673, 26482 => 29671, 26483 => 29662, - 26484 => 29626, 26485 => 29682, 26486 => 29711, 26487 => 29738, 26488 => 29787, - 26489 => 29734, 26490 => 29733, 26491 => 29736, 26492 => 29744, 26493 => 29742, - 26494 => 29740, 26657 => 29723, 26658 => 29722, 26659 => 29761, 26660 => 29788, - 26661 => 29783, 26662 => 29781, 26663 => 29785, 26664 => 29815, 26665 => 29805, - 26666 => 29822, 26667 => 29852, 26668 => 29838, 26669 => 29824, 26670 => 29825, - 26671 => 29831, 26672 => 29835, 26673 => 29854, 26674 => 29864, 26675 => 29865, - 26676 => 29840, 26677 => 29863, 26678 => 29906, 26679 => 29882, 26680 => 38890, - 26681 => 38891, 26682 => 38892, 26683 => 26444, 26684 => 26451, 26685 => 26462, - 26686 => 26440, 26687 => 26473, 26688 => 26533, 26689 => 26503, 26690 => 26474, - 26691 => 26483, 26692 => 26520, 26693 => 26535, 26694 => 26485, 26695 => 26536, - 26696 => 26526, 26697 => 26541, 26698 => 26507, 26699 => 26487, 26700 => 26492, - 26701 => 26608, 26702 => 26633, 26703 => 26584, 26704 => 26634, 26705 => 26601, - 26706 => 26544, 26707 => 26636, 26708 => 26585, 26709 => 26549, 26710 => 26586, - 26711 => 26547, 26712 => 26589, 26713 => 26624, 26714 => 26563, 26715 => 26552, - 26716 => 26594, 26717 => 26638, 26718 => 26561, 26719 => 26621, 26720 => 26674, - 26721 => 26675, 26722 => 26720, 26723 => 26721, 26724 => 26702, 26725 => 26722, - 26726 => 26692, 26727 => 26724, 26728 => 26755, 26729 => 26653, 26730 => 26709, - 26731 => 26726, 26732 => 26689, 26733 => 26727, 26734 => 26688, 26735 => 26686, - 26736 => 26698, 26737 => 26697, 26738 => 26665, 26739 => 26805, 26740 => 26767, - 26741 => 26740, 26742 => 26743, 26743 => 26771, 26744 => 26731, 26745 => 26818, - 26746 => 26990, 26747 => 26876, 26748 => 26911, 26749 => 26912, 26750 => 26873, - 26913 => 26916, 26914 => 26864, 26915 => 26891, 26916 => 26881, 26917 => 26967, - 26918 => 26851, 26919 => 26896, 26920 => 26993, 26921 => 26937, 26922 => 26976, - 26923 => 26946, 26924 => 26973, 26925 => 27012, 26926 => 26987, 26927 => 27008, - 26928 => 27032, 26929 => 27000, 26930 => 26932, 26931 => 27084, 26932 => 27015, - 26933 => 27016, 26934 => 27086, 26935 => 27017, 26936 => 26982, 26937 => 26979, - 26938 => 27001, 26939 => 27035, 26940 => 27047, 26941 => 27067, 26942 => 27051, - 26943 => 27053, 26944 => 27092, 26945 => 27057, 26946 => 27073, 26947 => 27082, - 26948 => 27103, 26949 => 27029, 26950 => 27104, 26951 => 27021, 26952 => 27135, - 26953 => 27183, 26954 => 27117, 26955 => 27159, 26956 => 27160, 26957 => 27237, - 26958 => 27122, 26959 => 27204, 26960 => 27198, 26961 => 27296, 26962 => 27216, - 26963 => 27227, 26964 => 27189, 26965 => 27278, 26966 => 27257, 26967 => 27197, - 26968 => 27176, 26969 => 27224, 26970 => 27260, 26971 => 27281, 26972 => 27280, - 26973 => 27305, 26974 => 27287, 26975 => 27307, 26976 => 29495, 26977 => 29522, - 26978 => 27521, 26979 => 27522, 26980 => 27527, 26981 => 27524, 26982 => 27538, - 26983 => 27539, 26984 => 27533, 26985 => 27546, 26986 => 27547, 26987 => 27553, - 26988 => 27562, 26989 => 36715, 26990 => 36717, 26991 => 36721, 26992 => 36722, - 26993 => 36723, 26994 => 36725, 26995 => 36726, 26996 => 36728, 26997 => 36727, - 26998 => 36729, 26999 => 36730, 27000 => 36732, 27001 => 36734, 27002 => 36737, - 27003 => 36738, 27004 => 36740, 27005 => 36743, 27006 => 36747, 27169 => 36749, - 27170 => 36750, 27171 => 36751, 27172 => 36760, 27173 => 36762, 27174 => 36558, - 27175 => 25099, 27176 => 25111, 27177 => 25115, 27178 => 25119, 27179 => 25122, - 27180 => 25121, 27181 => 25125, 27182 => 25124, 27183 => 25132, 27184 => 33255, - 27185 => 29935, 27186 => 29940, 27187 => 29951, 27188 => 29967, 27189 => 29969, - 27190 => 29971, 27191 => 25908, 27192 => 26094, 27193 => 26095, 27194 => 26096, - 27195 => 26122, 27196 => 26137, 27197 => 26482, 27198 => 26115, 27199 => 26133, - 27200 => 26112, 27201 => 28805, 27202 => 26359, 27203 => 26141, 27204 => 26164, - 27205 => 26161, 27206 => 26166, 27207 => 26165, 27208 => 32774, 27209 => 26207, - 27210 => 26196, 27211 => 26177, 27212 => 26191, 27213 => 26198, 27214 => 26209, - 27215 => 26199, 27216 => 26231, 27217 => 26244, 27218 => 26252, 27219 => 26279, - 27220 => 26269, 27221 => 26302, 27222 => 26331, 27223 => 26332, 27224 => 26342, - 27225 => 26345, 27226 => 36146, 27227 => 36147, 27228 => 36150, 27229 => 36155, - 27230 => 36157, 27231 => 36160, 27232 => 36165, 27233 => 36166, 27234 => 36168, - 27235 => 36169, 27236 => 36167, 27237 => 36173, 27238 => 36181, 27239 => 36185, - 27240 => 35271, 27241 => 35274, 27242 => 35275, 27243 => 35276, 27244 => 35278, - 27245 => 35279, 27246 => 35280, 27247 => 35281, 27248 => 29294, 27249 => 29343, - 27250 => 29277, 27251 => 29286, 27252 => 29295, 27253 => 29310, 27254 => 29311, - 27255 => 29316, 27256 => 29323, 27257 => 29325, 27258 => 29327, 27259 => 29330, - 27260 => 25352, 27261 => 25394, 27262 => 25520, 27425 => 25663, 27426 => 25816, - 27427 => 32772, 27428 => 27626, 27429 => 27635, 27430 => 27645, 27431 => 27637, - 27432 => 27641, 27433 => 27653, 27434 => 27655, 27435 => 27654, 27436 => 27661, - 27437 => 27669, 27438 => 27672, 27439 => 27673, 27440 => 27674, 27441 => 27681, - 27442 => 27689, 27443 => 27684, 27444 => 27690, 27445 => 27698, 27446 => 25909, - 27447 => 25941, 27448 => 25963, 27449 => 29261, 27450 => 29266, 27451 => 29270, - 27452 => 29232, 27453 => 34402, 27454 => 21014, 27455 => 32927, 27456 => 32924, - 27457 => 32915, 27458 => 32956, 27459 => 26378, 27460 => 32957, 27461 => 32945, - 27462 => 32939, 27463 => 32941, 27464 => 32948, 27465 => 32951, 27466 => 32999, - 27467 => 33000, 27468 => 33001, 27469 => 33002, 27470 => 32987, 27471 => 32962, - 27472 => 32964, 27473 => 32985, 27474 => 32973, 27475 => 32983, 27476 => 26384, - 27477 => 32989, 27478 => 33003, 27479 => 33009, 27480 => 33012, 27481 => 33005, - 27482 => 33037, 27483 => 33038, 27484 => 33010, 27485 => 33020, 27486 => 26389, - 27487 => 33042, 27488 => 35930, 27489 => 33078, 27490 => 33054, 27491 => 33068, - 27492 => 33048, 27493 => 33074, 27494 => 33096, 27495 => 33100, 27496 => 33107, - 27497 => 33140, 27498 => 33113, 27499 => 33114, 27500 => 33137, 27501 => 33120, - 27502 => 33129, 27503 => 33148, 27504 => 33149, 27505 => 33133, 27506 => 33127, - 27507 => 22605, 27508 => 23221, 27509 => 33160, 27510 => 33154, 27511 => 33169, - 27512 => 28373, 27513 => 33187, 27514 => 33194, 27515 => 33228, 27516 => 26406, - 27517 => 33226, 27518 => 33211, 27681 => 33217, 27682 => 33190, 27683 => 27428, - 27684 => 27447, 27685 => 27449, 27686 => 27459, 27687 => 27462, 27688 => 27481, - 27689 => 39121, 27690 => 39122, 27691 => 39123, 27692 => 39125, 27693 => 39129, - 27694 => 39130, 27695 => 27571, 27696 => 24384, 27697 => 27586, 27698 => 35315, - 27699 => 26000, 27700 => 40785, 27701 => 26003, 27702 => 26044, 27703 => 26054, - 27704 => 26052, 27705 => 26051, 27706 => 26060, 27707 => 26062, 27708 => 26066, - 27709 => 26070, 27710 => 28800, 27711 => 28828, 27712 => 28822, 27713 => 28829, - 27714 => 28859, 27715 => 28864, 27716 => 28855, 27717 => 28843, 27718 => 28849, - 27719 => 28904, 27720 => 28874, 27721 => 28944, 27722 => 28947, 27723 => 28950, - 27724 => 28975, 27725 => 28977, 27726 => 29043, 27727 => 29020, 27728 => 29032, - 27729 => 28997, 27730 => 29042, 27731 => 29002, 27732 => 29048, 27733 => 29050, - 27734 => 29080, 27735 => 29107, 27736 => 29109, 27737 => 29096, 27738 => 29088, - 27739 => 29152, 27740 => 29140, 27741 => 29159, 27742 => 29177, 27743 => 29213, - 27744 => 29224, 27745 => 28780, 27746 => 28952, 27747 => 29030, 27748 => 29113, - 27749 => 25150, 27750 => 25149, 27751 => 25155, 27752 => 25160, 27753 => 25161, - 27754 => 31035, 27755 => 31040, 27756 => 31046, 27757 => 31049, 27758 => 31067, - 27759 => 31068, 27760 => 31059, 27761 => 31066, 27762 => 31074, 27763 => 31063, - 27764 => 31072, 27765 => 31087, 27766 => 31079, 27767 => 31098, 27768 => 31109, - 27769 => 31114, 27770 => 31130, 27771 => 31143, 27772 => 31155, 27773 => 24529, - 27774 => 24528, 27937 => 24636, 27938 => 24669, 27939 => 24666, 27940 => 24679, - 27941 => 24641, 27942 => 24665, 27943 => 24675, 27944 => 24747, 27945 => 24838, - 27946 => 24845, 27947 => 24925, 27948 => 25001, 27949 => 24989, 27950 => 25035, - 27951 => 25041, 27952 => 25094, 27953 => 32896, 27954 => 32895, 27955 => 27795, - 27956 => 27894, 27957 => 28156, 27958 => 30710, 27959 => 30712, 27960 => 30720, - 27961 => 30729, 27962 => 30743, 27963 => 30744, 27964 => 30737, 27965 => 26027, - 27966 => 30765, 27967 => 30748, 27968 => 30749, 27969 => 30777, 27970 => 30778, - 27971 => 30779, 27972 => 30751, 27973 => 30780, 27974 => 30757, 27975 => 30764, - 27976 => 30755, 27977 => 30761, 27978 => 30798, 27979 => 30829, 27980 => 30806, - 27981 => 30807, 27982 => 30758, 27983 => 30800, 27984 => 30791, 27985 => 30796, - 27986 => 30826, 27987 => 30875, 27988 => 30867, 27989 => 30874, 27990 => 30855, - 27991 => 30876, 27992 => 30881, 27993 => 30883, 27994 => 30898, 27995 => 30905, - 27996 => 30885, 27997 => 30932, 27998 => 30937, 27999 => 30921, 28000 => 30956, - 28001 => 30962, 28002 => 30981, 28003 => 30964, 28004 => 30995, 28005 => 31012, - 28006 => 31006, 28007 => 31028, 28008 => 40859, 28009 => 40697, 28010 => 40699, - 28011 => 40700, 28012 => 30449, 28013 => 30468, 28014 => 30477, 28015 => 30457, - 28016 => 30471, 28017 => 30472, 28018 => 30490, 28019 => 30498, 28020 => 30489, - 28021 => 30509, 28022 => 30502, 28023 => 30517, 28024 => 30520, 28025 => 30544, - 28026 => 30545, 28027 => 30535, 28028 => 30531, 28029 => 30554, 28030 => 30568, - 28193 => 30562, 28194 => 30565, 28195 => 30591, 28196 => 30605, 28197 => 30589, - 28198 => 30592, 28199 => 30604, 28200 => 30609, 28201 => 30623, 28202 => 30624, - 28203 => 30640, 28204 => 30645, 28205 => 30653, 28206 => 30010, 28207 => 30016, - 28208 => 30030, 28209 => 30027, 28210 => 30024, 28211 => 30043, 28212 => 30066, - 28213 => 30073, 28214 => 30083, 28215 => 32600, 28216 => 32609, 28217 => 32607, - 28218 => 35400, 28219 => 32616, 28220 => 32628, 28221 => 32625, 28222 => 32633, - 28223 => 32641, 28224 => 32638, 28225 => 30413, 28226 => 30437, 28227 => 34866, - 28228 => 38021, 28229 => 38022, 28230 => 38023, 28231 => 38027, 28232 => 38026, - 28233 => 38028, 28234 => 38029, 28235 => 38031, 28236 => 38032, 28237 => 38036, - 28238 => 38039, 28239 => 38037, 28240 => 38042, 28241 => 38043, 28242 => 38044, - 28243 => 38051, 28244 => 38052, 28245 => 38059, 28246 => 38058, 28247 => 38061, - 28248 => 38060, 28249 => 38063, 28250 => 38064, 28251 => 38066, 28252 => 38068, - 28253 => 38070, 28254 => 38071, 28255 => 38072, 28256 => 38073, 28257 => 38074, - 28258 => 38076, 28259 => 38077, 28260 => 38079, 28261 => 38084, 28262 => 38088, - 28263 => 38089, 28264 => 38090, 28265 => 38091, 28266 => 38092, 28267 => 38093, - 28268 => 38094, 28269 => 38096, 28270 => 38097, 28271 => 38098, 28272 => 38101, - 28273 => 38102, 28274 => 38103, 28275 => 38105, 28276 => 38104, 28277 => 38107, - 28278 => 38110, 28279 => 38111, 28280 => 38112, 28281 => 38114, 28282 => 38116, - 28283 => 38117, 28284 => 38119, 28285 => 38120, 28286 => 38122, 28449 => 38121, - 28450 => 38123, 28451 => 38126, 28452 => 38127, 28453 => 38131, 28454 => 38132, - 28455 => 38133, 28456 => 38135, 28457 => 38137, 28458 => 38140, 28459 => 38141, - 28460 => 38143, 28461 => 38147, 28462 => 38146, 28463 => 38150, 28464 => 38151, - 28465 => 38153, 28466 => 38154, 28467 => 38157, 28468 => 38158, 28469 => 38159, - 28470 => 38162, 28471 => 38163, 28472 => 38164, 28473 => 38165, 28474 => 38166, - 28475 => 38168, 28476 => 38171, 28477 => 38173, 28478 => 38174, 28479 => 38175, - 28480 => 38178, 28481 => 38186, 28482 => 38187, 28483 => 38185, 28484 => 38188, - 28485 => 38193, 28486 => 38194, 28487 => 38196, 28488 => 38198, 28489 => 38199, - 28490 => 38200, 28491 => 38204, 28492 => 38206, 28493 => 38207, 28494 => 38210, - 28495 => 38197, 28496 => 38212, 28497 => 38213, 28498 => 38214, 28499 => 38217, - 28500 => 38220, 28501 => 38222, 28502 => 38223, 28503 => 38226, 28504 => 38227, - 28505 => 38228, 28506 => 38230, 28507 => 38231, 28508 => 38232, 28509 => 38233, - 28510 => 38235, 28511 => 38238, 28512 => 38239, 28513 => 38237, 28514 => 38241, - 28515 => 38242, 28516 => 38244, 28517 => 38245, 28518 => 38246, 28519 => 38247, - 28520 => 38248, 28521 => 38249, 28522 => 38250, 28523 => 38251, 28524 => 38252, - 28525 => 38255, 28526 => 38257, 28527 => 38258, 28528 => 38259, 28529 => 38202, - 28530 => 30695, 28531 => 30700, 28532 => 38601, 28533 => 31189, 28534 => 31213, - 28535 => 31203, 28536 => 31211, 28537 => 31238, 28538 => 23879, 28539 => 31235, - 28540 => 31234, 28541 => 31262, 28542 => 31252, 28705 => 31289, 28706 => 31287, - 28707 => 31313, 28708 => 40655, 28709 => 39333, 28710 => 31344, 28711 => 30344, - 28712 => 30350, 28713 => 30355, 28714 => 30361, 28715 => 30372, 28716 => 29918, - 28717 => 29920, 28718 => 29996, 28719 => 40480, 28720 => 40482, 28721 => 40488, - 28722 => 40489, 28723 => 40490, 28724 => 40491, 28725 => 40492, 28726 => 40498, - 28727 => 40497, 28728 => 40502, 28729 => 40504, 28730 => 40503, 28731 => 40505, - 28732 => 40506, 28733 => 40510, 28734 => 40513, 28735 => 40514, 28736 => 40516, - 28737 => 40518, 28738 => 40519, 28739 => 40520, 28740 => 40521, 28741 => 40523, - 28742 => 40524, 28743 => 40526, 28744 => 40529, 28745 => 40533, 28746 => 40535, - 28747 => 40538, 28748 => 40539, 28749 => 40540, 28750 => 40542, 28751 => 40547, - 28752 => 40550, 28753 => 40551, 28754 => 40552, 28755 => 40553, 28756 => 40554, - 28757 => 40555, 28758 => 40556, 28759 => 40561, 28760 => 40557, 28761 => 40563, - 28762 => 30098, 28763 => 30100, 28764 => 30102, 28765 => 30112, 28766 => 30109, - 28767 => 30124, 28768 => 30115, 28769 => 30131, 28770 => 30132, 28771 => 30136, - 28772 => 30148, 28773 => 30129, 28774 => 30128, 28775 => 30147, 28776 => 30146, - 28777 => 30166, 28778 => 30157, 28779 => 30179, 28780 => 30184, 28781 => 30182, - 28782 => 30180, 28783 => 30187, 28784 => 30183, 28785 => 30211, 28786 => 30193, - 28787 => 30204, 28788 => 30207, 28789 => 30224, 28790 => 30208, 28791 => 30213, - 28792 => 30220, 28793 => 30231, 28794 => 30218, 28795 => 30245, 28796 => 30232, - 28797 => 30229, 28798 => 30233, 28961 => 30235, 28962 => 30268, 28963 => 30242, - 28964 => 30240, 28965 => 30272, 28966 => 30253, 28967 => 30256, 28968 => 30271, - 28969 => 30261, 28970 => 30275, 28971 => 30270, 28972 => 30259, 28973 => 30285, - 28974 => 30302, 28975 => 30292, 28976 => 30300, 28977 => 30294, 28978 => 30315, - 28979 => 30319, 28980 => 32714, 28981 => 31462, 28982 => 31352, 28983 => 31353, - 28984 => 31360, 28985 => 31366, 28986 => 31368, 28987 => 31381, 28988 => 31398, - 28989 => 31392, 28990 => 31404, 28991 => 31400, 28992 => 31405, 28993 => 31411, - 28994 => 34916, 28995 => 34921, 28996 => 34930, 28997 => 34941, 28998 => 34943, - 28999 => 34946, 29000 => 34978, 29001 => 35014, 29002 => 34999, 29003 => 35004, - 29004 => 35017, 29005 => 35042, 29006 => 35022, 29007 => 35043, 29008 => 35045, - 29009 => 35057, 29010 => 35098, 29011 => 35068, 29012 => 35048, 29013 => 35070, - 29014 => 35056, 29015 => 35105, 29016 => 35097, 29017 => 35091, 29018 => 35099, - 29019 => 35082, 29020 => 35124, 29021 => 35115, 29022 => 35126, 29023 => 35137, - 29024 => 35174, 29025 => 35195, 29026 => 30091, 29027 => 32997, 29028 => 30386, - 29029 => 30388, 29030 => 30684, 29031 => 32786, 29032 => 32788, 29033 => 32790, - 29034 => 32796, 29035 => 32800, 29036 => 32802, 29037 => 32805, 29038 => 32806, - 29039 => 32807, 29040 => 32809, 29041 => 32808, 29042 => 32817, 29043 => 32779, - 29044 => 32821, 29045 => 32835, 29046 => 32838, 29047 => 32845, 29048 => 32850, - 29049 => 32873, 29050 => 32881, 29051 => 35203, 29052 => 39032, 29053 => 39040, - 29054 => 39043, 29217 => 39049, 29218 => 39052, 29219 => 39053, 29220 => 39055, - 29221 => 39060, 29222 => 39066, 29223 => 39067, 29224 => 39070, 29225 => 39071, - 29226 => 39073, 29227 => 39074, 29228 => 39077, 29229 => 39078, 29230 => 34381, - 29231 => 34388, 29232 => 34412, 29233 => 34414, 29234 => 34431, 29235 => 34426, - 29236 => 34428, 29237 => 34427, 29238 => 34472, 29239 => 34445, 29240 => 34443, - 29241 => 34476, 29242 => 34461, 29243 => 34471, 29244 => 34467, 29245 => 34474, - 29246 => 34451, 29247 => 34473, 29248 => 34486, 29249 => 34500, 29250 => 34485, - 29251 => 34510, 29252 => 34480, 29253 => 34490, 29254 => 34481, 29255 => 34479, - 29256 => 34505, 29257 => 34511, 29258 => 34484, 29259 => 34537, 29260 => 34545, - 29261 => 34546, 29262 => 34541, 29263 => 34547, 29264 => 34512, 29265 => 34579, - 29266 => 34526, 29267 => 34548, 29268 => 34527, 29269 => 34520, 29270 => 34513, - 29271 => 34563, 29272 => 34567, 29273 => 34552, 29274 => 34568, 29275 => 34570, - 29276 => 34573, 29277 => 34569, 29278 => 34595, 29279 => 34619, 29280 => 34590, - 29281 => 34597, 29282 => 34606, 29283 => 34586, 29284 => 34622, 29285 => 34632, - 29286 => 34612, 29287 => 34609, 29288 => 34601, 29289 => 34615, 29290 => 34623, - 29291 => 34690, 29292 => 34594, 29293 => 34685, 29294 => 34686, 29295 => 34683, - 29296 => 34656, 29297 => 34672, 29298 => 34636, 29299 => 34670, 29300 => 34699, - 29301 => 34643, 29302 => 34659, 29303 => 34684, 29304 => 34660, 29305 => 34649, - 29306 => 34661, 29307 => 34707, 29308 => 34735, 29309 => 34728, 29310 => 34770, - 29473 => 34758, 29474 => 34696, 29475 => 34693, 29476 => 34733, 29477 => 34711, - 29478 => 34691, 29479 => 34731, 29480 => 34789, 29481 => 34732, 29482 => 34741, - 29483 => 34739, 29484 => 34763, 29485 => 34771, 29486 => 34749, 29487 => 34769, - 29488 => 34752, 29489 => 34762, 29490 => 34779, 29491 => 34794, 29492 => 34784, - 29493 => 34798, 29494 => 34838, 29495 => 34835, 29496 => 34814, 29497 => 34826, - 29498 => 34843, 29499 => 34849, 29500 => 34873, 29501 => 34876, 29502 => 32566, - 29503 => 32578, 29504 => 32580, 29505 => 32581, 29506 => 33296, 29507 => 31482, - 29508 => 31485, 29509 => 31496, 29510 => 31491, 29511 => 31492, 29512 => 31509, - 29513 => 31498, 29514 => 31531, 29515 => 31503, 29516 => 31559, 29517 => 31544, - 29518 => 31530, 29519 => 31513, 29520 => 31534, 29521 => 31537, 29522 => 31520, - 29523 => 31525, 29524 => 31524, 29525 => 31539, 29526 => 31550, 29527 => 31518, - 29528 => 31576, 29529 => 31578, 29530 => 31557, 29531 => 31605, 29532 => 31564, - 29533 => 31581, 29534 => 31584, 29535 => 31598, 29536 => 31611, 29537 => 31586, - 29538 => 31602, 29539 => 31601, 29540 => 31632, 29541 => 31654, 29542 => 31655, - 29543 => 31672, 29544 => 31660, 29545 => 31645, 29546 => 31656, 29547 => 31621, - 29548 => 31658, 29549 => 31644, 29550 => 31650, 29551 => 31659, 29552 => 31668, - 29553 => 31697, 29554 => 31681, 29555 => 31692, 29556 => 31709, 29557 => 31706, - 29558 => 31717, 29559 => 31718, 29560 => 31722, 29561 => 31756, 29562 => 31742, - 29563 => 31740, 29564 => 31759, 29565 => 31766, 29566 => 31755, 29729 => 31775, - 29730 => 31786, 29731 => 31782, 29732 => 31800, 29733 => 31809, 29734 => 31808, - 29735 => 33278, 29736 => 33281, 29737 => 33282, 29738 => 33284, 29739 => 33260, - 29740 => 34884, 29741 => 33313, 29742 => 33314, 29743 => 33315, 29744 => 33325, - 29745 => 33327, 29746 => 33320, 29747 => 33323, 29748 => 33336, 29749 => 33339, - 29750 => 33331, 29751 => 33332, 29752 => 33342, 29753 => 33348, 29754 => 33353, - 29755 => 33355, 29756 => 33359, 29757 => 33370, 29758 => 33375, 29759 => 33384, - 29760 => 34942, 29761 => 34949, 29762 => 34952, 29763 => 35032, 29764 => 35039, - 29765 => 35166, 29766 => 32669, 29767 => 32671, 29768 => 32679, 29769 => 32687, - 29770 => 32688, 29771 => 32690, 29772 => 31868, 29773 => 25929, 29774 => 31889, - 29775 => 31901, 29776 => 31900, 29777 => 31902, 29778 => 31906, 29779 => 31922, - 29780 => 31932, 29781 => 31933, 29782 => 31937, 29783 => 31943, 29784 => 31948, - 29785 => 31949, 29786 => 31944, 29787 => 31941, 29788 => 31959, 29789 => 31976, - 29790 => 33390, 29791 => 26280, 29792 => 32703, 29793 => 32718, 29794 => 32725, - 29795 => 32741, 29796 => 32737, 29797 => 32742, 29798 => 32745, 29799 => 32750, - 29800 => 32755, 29801 => 31992, 29802 => 32119, 29803 => 32166, 29804 => 32174, - 29805 => 32327, 29806 => 32411, 29807 => 40632, 29808 => 40628, 29809 => 36211, - 29810 => 36228, 29811 => 36244, 29812 => 36241, 29813 => 36273, 29814 => 36199, - 29815 => 36205, 29816 => 35911, 29817 => 35913, 29818 => 37194, 29819 => 37200, - 29820 => 37198, 29821 => 37199, 29822 => 37220, 29985 => 37218, 29986 => 37217, - 29987 => 37232, 29988 => 37225, 29989 => 37231, 29990 => 37245, 29991 => 37246, - 29992 => 37234, 29993 => 37236, 29994 => 37241, 29995 => 37260, 29996 => 37253, - 29997 => 37264, 29998 => 37261, 29999 => 37265, 30000 => 37282, 30001 => 37283, - 30002 => 37290, 30003 => 37293, 30004 => 37294, 30005 => 37295, 30006 => 37301, - 30007 => 37300, 30008 => 37306, 30009 => 35925, 30010 => 40574, 30011 => 36280, - 30012 => 36331, 30013 => 36357, 30014 => 36441, 30015 => 36457, 30016 => 36277, - 30017 => 36287, 30018 => 36284, 30019 => 36282, 30020 => 36292, 30021 => 36310, - 30022 => 36311, 30023 => 36314, 30024 => 36318, 30025 => 36302, 30026 => 36303, - 30027 => 36315, 30028 => 36294, 30029 => 36332, 30030 => 36343, 30031 => 36344, - 30032 => 36323, 30033 => 36345, 30034 => 36347, 30035 => 36324, 30036 => 36361, - 30037 => 36349, 30038 => 36372, 30039 => 36381, 30040 => 36383, 30041 => 36396, - 30042 => 36398, 30043 => 36387, 30044 => 36399, 30045 => 36410, 30046 => 36416, - 30047 => 36409, 30048 => 36405, 30049 => 36413, 30050 => 36401, 30051 => 36425, - 30052 => 36417, 30053 => 36418, 30054 => 36433, 30055 => 36434, 30056 => 36426, - 30057 => 36464, 30058 => 36470, 30059 => 36476, 30060 => 36463, 30061 => 36468, - 30062 => 36485, 30063 => 36495, 30064 => 36500, 30065 => 36496, 30066 => 36508, - 30067 => 36510, 30068 => 35960, 30069 => 35970, 30070 => 35978, 30071 => 35973, - 30072 => 35992, 30073 => 35988, 30074 => 26011, 30075 => 35286, 30076 => 35294, - 30077 => 35290, 30078 => 35292, 30241 => 35301, 30242 => 35307, 30243 => 35311, - 30244 => 35390, 30245 => 35622, 30246 => 38739, 30247 => 38633, 30248 => 38643, - 30249 => 38639, 30250 => 38662, 30251 => 38657, 30252 => 38664, 30253 => 38671, - 30254 => 38670, 30255 => 38698, 30256 => 38701, 30257 => 38704, 30258 => 38718, - 30259 => 40832, 30260 => 40835, 30261 => 40837, 30262 => 40838, 30263 => 40839, - 30264 => 40840, 30265 => 40841, 30266 => 40842, 30267 => 40844, 30268 => 40702, - 30269 => 40715, 30270 => 40717, 30271 => 38585, 30272 => 38588, 30273 => 38589, - 30274 => 38606, 30275 => 38610, 30276 => 30655, 30277 => 38624, 30278 => 37518, - 30279 => 37550, 30280 => 37576, 30281 => 37694, 30282 => 37738, 30283 => 37834, - 30284 => 37775, 30285 => 37950, 30286 => 37995, 30287 => 40063, 30288 => 40066, - 30289 => 40069, 30290 => 40070, 30291 => 40071, 30292 => 40072, 30293 => 31267, - 30294 => 40075, 30295 => 40078, 30296 => 40080, 30297 => 40081, 30298 => 40082, - 30299 => 40084, 30300 => 40085, 30301 => 40090, 30302 => 40091, 30303 => 40094, - 30304 => 40095, 30305 => 40096, 30306 => 40097, 30307 => 40098, 30308 => 40099, - 30309 => 40101, 30310 => 40102, 30311 => 40103, 30312 => 40104, 30313 => 40105, - 30314 => 40107, 30315 => 40109, 30316 => 40110, 30317 => 40112, 30318 => 40113, - 30319 => 40114, 30320 => 40115, 30321 => 40116, 30322 => 40117, 30323 => 40118, - 30324 => 40119, 30325 => 40122, 30326 => 40123, 30327 => 40124, 30328 => 40125, - 30329 => 40132, 30330 => 40133, 30331 => 40134, 30332 => 40135, 30333 => 40138, - 30334 => 40139, 30497 => 40140, 30498 => 40141, 30499 => 40142, 30500 => 40143, - 30501 => 40144, 30502 => 40147, 30503 => 40148, 30504 => 40149, 30505 => 40151, - 30506 => 40152, 30507 => 40153, 30508 => 40156, 30509 => 40157, 30510 => 40159, - 30511 => 40162, 30512 => 38780, 30513 => 38789, 30514 => 38801, 30515 => 38802, - 30516 => 38804, 30517 => 38831, 30518 => 38827, 30519 => 38819, 30520 => 38834, - 30521 => 38836, 30522 => 39601, 30523 => 39600, 30524 => 39607, 30525 => 40536, - 30526 => 39606, 30527 => 39610, 30528 => 39612, 30529 => 39617, 30530 => 39616, - 30531 => 39621, 30532 => 39618, 30533 => 39627, 30534 => 39628, 30535 => 39633, - 30536 => 39749, 30537 => 39747, 30538 => 39751, 30539 => 39753, 30540 => 39752, - 30541 => 39757, 30542 => 39761, 30543 => 39144, 30544 => 39181, 30545 => 39214, - 30546 => 39253, 30547 => 39252, 30548 => 39647, 30549 => 39649, 30550 => 39654, - 30551 => 39663, 30552 => 39659, 30553 => 39675, 30554 => 39661, 30555 => 39673, - 30556 => 39688, 30557 => 39695, 30558 => 39699, 30559 => 39711, 30560 => 39715, - 30561 => 40637, 30562 => 40638, 30563 => 32315, 30564 => 40578, 30565 => 40583, - 30566 => 40584, 30567 => 40587, 30568 => 40594, 30569 => 37846, 30570 => 40605, - 30571 => 40607, 30572 => 40667, 30573 => 40668, 30574 => 40669, 30575 => 40672, - 30576 => 40671, 30577 => 40674, 30578 => 40681, 30579 => 40679, 30580 => 40677, - 30581 => 40682, 30582 => 40687, 30583 => 40738, 30584 => 40748, 30585 => 40751, - 30586 => 40761, 30587 => 40759, 30588 => 40765, 30589 => 40766, 30590 => 40772, - 0 => 0 ); - - function gb2utf8($gb) { - if( !trim($gb) ) return $gb; - $utf8=''; - while($gb) { - if( ord(substr($gb,0,1)) > 127 ) { - $t=substr($gb,0,2); - $gb=substr($gb,2); - $utf8 .= $this->u2utf8($this->codetable[hexdec(bin2hex($t))-0x8080]); - } - else { - $t=substr($gb,0,1); - $gb=substr($gb,1); - $utf8 .= $this->u2utf8($t); - } - } - return $utf8; - } - - function u2utf8($c) { - $str=''; - if ($c < 0x80) { - $str.=$c; - } - else if ($c < 0x800) { - $str.=chr(0xC0 | $c>>6); - $str.=chr(0x80 | $c & 0x3F); - } - else if ($c < 0x10000) { - $str.=chr(0xE0 | $c>>12); - $str.=chr(0x80 | $c>>6 & 0x3F); - $str.=chr(0x80 | $c & 0x3F); - } - else if ($c < 0x200000) { - $str.=chr(0xF0 | $c>>18); - $str.=chr(0x80 | $c>>12 & 0x3F); - $str.=chr(0x80 | $c>>6 & 0x3F); - $str.=chr(0x80 | $c & 0x3F); - } - return $str; - } - -} // END Class - -?> + 12288, 8482 => 12289, 8483 => 12290, 8484 => 12539, 8485 => 713, + 8486 => 711, 8487 => 168, 8488 => 12291, 8489 => 12293, 8490 => 8213, + 8491 => 65374, 8492 => 8214, 8493 => 8230, 8494 => 8216, 8495 => 8217, + 8496 => 8220, 8497 => 8221, 8498 => 12308, 8499 => 12309, 8500 => 12296, + 8501 => 12297, 8502 => 12298, 8503 => 12299, 8504 => 12300, 8505 => 12301, + 8506 => 12302, 8507 => 12303, 8508 => 12310, 8509 => 12311, 8510 => 12304, + 8511 => 12305, 8512 => 177, 8513 => 215, 8514 => 247, 8515 => 8758, + 8516 => 8743, 8517 => 8744, 8518 => 8721, 8519 => 8719, 8520 => 8746, + 8521 => 8745, 8522 => 8712, 8523 => 8759, 8524 => 8730, 8525 => 8869, + 8526 => 8741, 8527 => 8736, 8528 => 8978, 8529 => 8857, 8530 => 8747, + 8531 => 8750, 8532 => 8801, 8533 => 8780, 8534 => 8776, 8535 => 8765, + 8536 => 8733, 8537 => 8800, 8538 => 8814, 8539 => 8815, 8540 => 8804, + 8541 => 8805, 8542 => 8734, 8543 => 8757, 8544 => 8756, 8545 => 9794, + 8546 => 9792, 8547 => 176, 8548 => 8242, 8549 => 8243, 8550 => 8451, + 8551 => 65284, 8552 => 164, 8553 => 65504, 8554 => 65505, 8555 => 8240, + 8556 => 167, 8557 => 8470, 8558 => 9734, 8559 => 9733, 8560 => 9675, + 8561 => 9679, 8562 => 9678, 8563 => 9671, 8564 => 9670, 8565 => 9633, + 8566 => 9632, 8567 => 9651, 8568 => 9650, 8569 => 8251, 8570 => 8594, + 8571 => 8592, 8572 => 8593, 8573 => 8595, 8574 => 12307, 8753 => 9352, + 8754 => 9353, 8755 => 9354, 8756 => 9355, 8757 => 9356, 8758 => 9357, + 8759 => 9358, 8760 => 9359, 8761 => 9360, 8762 => 9361, 8763 => 9362, + 8764 => 9363, 8765 => 9364, 8766 => 9365, 8767 => 9366, 8768 => 9367, + 8769 => 9368, 8770 => 9369, 8771 => 9370, 8772 => 9371, 8773 => 9332, + 8774 => 9333, 8775 => 9334, 8776 => 9335, 8777 => 9336, 8778 => 9337, + 8779 => 9338, 8780 => 9339, 8781 => 9340, 8782 => 9341, 8783 => 9342, + 8784 => 9343, 8785 => 9344, 8786 => 9345, 8787 => 9346, 8788 => 9347, + 8789 => 9348, 8790 => 9349, 8791 => 9350, 8792 => 9351, 8793 => 9312, + 8794 => 9313, 8795 => 9314, 8796 => 9315, 8797 => 9316, 8798 => 9317, + 8799 => 9318, 8800 => 9319, 8801 => 9320, 8802 => 9321, 8805 => 12832, + 8806 => 12833, 8807 => 12834, 8808 => 12835, 8809 => 12836, 8810 => 12837, + 8811 => 12838, 8812 => 12839, 8813 => 12840, 8814 => 12841, 8817 => 8544, + 8818 => 8545, 8819 => 8546, 8820 => 8547, 8821 => 8548, 8822 => 8549, + 8823 => 8550, 8824 => 8551, 8825 => 8552, 8826 => 8553, 8827 => 8554, + 8828 => 8555, 8993 => 65281, 8994 => 65282, 8995 => 65283, 8996 => 65509, + 8997 => 65285, 8998 => 65286, 8999 => 65287, 9000 => 65288, 9001 => 65289, + 9002 => 65290, 9003 => 65291, 9004 => 65292, 9005 => 65293, 9006 => 65294, + 9007 => 65295, 9008 => 65296, 9009 => 65297, 9010 => 65298, 9011 => 65299, + 9012 => 65300, 9013 => 65301, 9014 => 65302, 9015 => 65303, 9016 => 65304, + 9017 => 65305, 9018 => 65306, 9019 => 65307, 9020 => 65308, 9021 => 65309, + 9022 => 65310, 9023 => 65311, 9024 => 65312, 9025 => 65313, 9026 => 65314, + 9027 => 65315, 9028 => 65316, 9029 => 65317, 9030 => 65318, 9031 => 65319, + 9032 => 65320, 9033 => 65321, 9034 => 65322, 9035 => 65323, 9036 => 65324, + 9037 => 65325, 9038 => 65326, 9039 => 65327, 9040 => 65328, 9041 => 65329, + 9042 => 65330, 9043 => 65331, 9044 => 65332, 9045 => 65333, 9046 => 65334, + 9047 => 65335, 9048 => 65336, 9049 => 65337, 9050 => 65338, 9051 => 65339, + 9052 => 65340, 9053 => 65341, 9054 => 65342, 9055 => 65343, 9056 => 65344, + 9057 => 65345, 9058 => 65346, 9059 => 65347, 9060 => 65348, 9061 => 65349, + 9062 => 65350, 9063 => 65351, 9064 => 65352, 9065 => 65353, 9066 => 65354, + 9067 => 65355, 9068 => 65356, 9069 => 65357, 9070 => 65358, 9071 => 65359, + 9072 => 65360, 9073 => 65361, 9074 => 65362, 9075 => 65363, 9076 => 65364, + 9077 => 65365, 9078 => 65366, 9079 => 65367, 9080 => 65368, 9081 => 65369, + 9082 => 65370, 9083 => 65371, 9084 => 65372, 9085 => 65373, 9086 => 65507, + 9249 => 12353, 9250 => 12354, 9251 => 12355, 9252 => 12356, 9253 => 12357, + 9254 => 12358, 9255 => 12359, 9256 => 12360, 9257 => 12361, 9258 => 12362, + 9259 => 12363, 9260 => 12364, 9261 => 12365, 9262 => 12366, 9263 => 12367, + 9264 => 12368, 9265 => 12369, 9266 => 12370, 9267 => 12371, 9268 => 12372, + 9269 => 12373, 9270 => 12374, 9271 => 12375, 9272 => 12376, 9273 => 12377, + 9274 => 12378, 9275 => 12379, 9276 => 12380, 9277 => 12381, 9278 => 12382, + 9279 => 12383, 9280 => 12384, 9281 => 12385, 9282 => 12386, 9283 => 12387, + 9284 => 12388, 9285 => 12389, 9286 => 12390, 9287 => 12391, 9288 => 12392, + 9289 => 12393, 9290 => 12394, 9291 => 12395, 9292 => 12396, 9293 => 12397, + 9294 => 12398, 9295 => 12399, 9296 => 12400, 9297 => 12401, 9298 => 12402, + 9299 => 12403, 9300 => 12404, 9301 => 12405, 9302 => 12406, 9303 => 12407, + 9304 => 12408, 9305 => 12409, 9306 => 12410, 9307 => 12411, 9308 => 12412, + 9309 => 12413, 9310 => 12414, 9311 => 12415, 9312 => 12416, 9313 => 12417, + 9314 => 12418, 9315 => 12419, 9316 => 12420, 9317 => 12421, 9318 => 12422, + 9319 => 12423, 9320 => 12424, 9321 => 12425, 9322 => 12426, 9323 => 12427, + 9324 => 12428, 9325 => 12429, 9326 => 12430, 9327 => 12431, 9328 => 12432, + 9329 => 12433, 9330 => 12434, 9331 => 12435, 9505 => 12449, 9506 => 12450, + 9507 => 12451, 9508 => 12452, 9509 => 12453, 9510 => 12454, 9511 => 12455, + 9512 => 12456, 9513 => 12457, 9514 => 12458, 9515 => 12459, 9516 => 12460, + 9517 => 12461, 9518 => 12462, 9519 => 12463, 9520 => 12464, 9521 => 12465, + 9522 => 12466, 9523 => 12467, 9524 => 12468, 9525 => 12469, 9526 => 12470, + 9527 => 12471, 9528 => 12472, 9529 => 12473, 9530 => 12474, 9531 => 12475, + 9532 => 12476, 9533 => 12477, 9534 => 12478, 9535 => 12479, 9536 => 12480, + 9537 => 12481, 9538 => 12482, 9539 => 12483, 9540 => 12484, 9541 => 12485, + 9542 => 12486, 9543 => 12487, 9544 => 12488, 9545 => 12489, 9546 => 12490, + 9547 => 12491, 9548 => 12492, 9549 => 12493, 9550 => 12494, 9551 => 12495, + 9552 => 12496, 9553 => 12497, 9554 => 12498, 9555 => 12499, 9556 => 12500, + 9557 => 12501, 9558 => 12502, 9559 => 12503, 9560 => 12504, 9561 => 12505, + 9562 => 12506, 9563 => 12507, 9564 => 12508, 9565 => 12509, 9566 => 12510, + 9567 => 12511, 9568 => 12512, 9569 => 12513, 9570 => 12514, 9571 => 12515, + 9572 => 12516, 9573 => 12517, 9574 => 12518, 9575 => 12519, 9576 => 12520, + 9577 => 12521, 9578 => 12522, 9579 => 12523, 9580 => 12524, 9581 => 12525, + 9582 => 12526, 9583 => 12527, 9584 => 12528, 9585 => 12529, 9586 => 12530, + 9587 => 12531, 9588 => 12532, 9589 => 12533, 9590 => 12534, 9761 => 913, + 9762 => 914, 9763 => 915, 9764 => 916, 9765 => 917, 9766 => 918, + 9767 => 919, 9768 => 920, 9769 => 921, 9770 => 922, 9771 => 923, + 9772 => 924, 9773 => 925, 9774 => 926, 9775 => 927, 9776 => 928, + 9777 => 929, 9778 => 931, 9779 => 932, 9780 => 933, 9781 => 934, + 9782 => 935, 9783 => 936, 9784 => 937, 9793 => 945, 9794 => 946, + 9795 => 947, 9796 => 948, 9797 => 949, 9798 => 950, 9799 => 951, + 9800 => 952, 9801 => 953, 9802 => 954, 9803 => 955, 9804 => 956, + 9805 => 957, 9806 => 958, 9807 => 959, 9808 => 960, 9809 => 961, + 9810 => 963, 9811 => 964, 9812 => 965, 9813 => 966, 9814 => 967, + 9815 => 968, 9816 => 969, 10017 => 1040, 10018 => 1041, 10019 => 1042, + 10020 => 1043, 10021 => 1044, 10022 => 1045, 10023 => 1025, 10024 => 1046, + 10025 => 1047, 10026 => 1048, 10027 => 1049, 10028 => 1050, 10029 => 1051, + 10030 => 1052, 10031 => 1053, 10032 => 1054, 10033 => 1055, 10034 => 1056, + 10035 => 1057, 10036 => 1058, 10037 => 1059, 10038 => 1060, 10039 => 1061, + 10040 => 1062, 10041 => 1063, 10042 => 1064, 10043 => 1065, 10044 => 1066, + 10045 => 1067, 10046 => 1068, 10047 => 1069, 10048 => 1070, 10049 => 1071, + 10065 => 1072, 10066 => 1073, 10067 => 1074, 10068 => 1075, 10069 => 1076, + 10070 => 1077, 10071 => 1105, 10072 => 1078, 10073 => 1079, 10074 => 1080, + 10075 => 1081, 10076 => 1082, 10077 => 1083, 10078 => 1084, 10079 => 1085, + 10080 => 1086, 10081 => 1087, 10082 => 1088, 10083 => 1089, 10084 => 1090, + 10085 => 1091, 10086 => 1092, 10087 => 1093, 10088 => 1094, 10089 => 1095, + 10090 => 1096, 10091 => 1097, 10092 => 1098, 10093 => 1099, 10094 => 1100, + 10095 => 1101, 10096 => 1102, 10097 => 1103, 10273 => 257, 10274 => 225, + 10275 => 462, 10276 => 224, 10277 => 275, 10278 => 233, 10279 => 283, + 10280 => 232, 10281 => 299, 10282 => 237, 10283 => 464, 10284 => 236, + 10285 => 333, 10286 => 243, 10287 => 466, 10288 => 242, 10289 => 363, + 10290 => 250, 10291 => 468, 10292 => 249, 10293 => 470, 10294 => 472, + 10295 => 474, 10296 => 476, 10297 => 252, 10298 => 234, 10309 => 12549, + 10310 => 12550, 10311 => 12551, 10312 => 12552, 10313 => 12553, 10314 => 12554, + 10315 => 12555, 10316 => 12556, 10317 => 12557, 10318 => 12558, 10319 => 12559, + 10320 => 12560, 10321 => 12561, 10322 => 12562, 10323 => 12563, 10324 => 12564, + 10325 => 12565, 10326 => 12566, 10327 => 12567, 10328 => 12568, 10329 => 12569, + 10330 => 12570, 10331 => 12571, 10332 => 12572, 10333 => 12573, 10334 => 12574, + 10335 => 12575, 10336 => 12576, 10337 => 12577, 10338 => 12578, 10339 => 12579, + 10340 => 12580, 10341 => 12581, 10342 => 12582, 10343 => 12583, 10344 => 12584, + 10345 => 12585, 10532 => 9472, 10533 => 9473, 10534 => 9474, 10535 => 9475, + 10536 => 9476, 10537 => 9477, 10538 => 9478, 10539 => 9479, 10540 => 9480, + 10541 => 9481, 10542 => 9482, 10543 => 9483, 10544 => 9484, 10545 => 9485, + 10546 => 9486, 10547 => 9487, 10548 => 9488, 10549 => 9489, 10550 => 9490, + 10551 => 9491, 10552 => 9492, 10553 => 9493, 10554 => 9494, 10555 => 9495, + 10556 => 9496, 10557 => 9497, 10558 => 9498, 10559 => 9499, 10560 => 9500, + 10561 => 9501, 10562 => 9502, 10563 => 9503, 10564 => 9504, 10565 => 9505, + 10566 => 9506, 10567 => 9507, 10568 => 9508, 10569 => 9509, 10570 => 9510, + 10571 => 9511, 10572 => 9512, 10573 => 9513, 10574 => 9514, 10575 => 9515, + 10576 => 9516, 10577 => 9517, 10578 => 9518, 10579 => 9519, 10580 => 9520, + 10581 => 9521, 10582 => 9522, 10583 => 9523, 10584 => 9524, 10585 => 9525, + 10586 => 9526, 10587 => 9527, 10588 => 9528, 10589 => 9529, 10590 => 9530, + 10591 => 9531, 10592 => 9532, 10593 => 9533, 10594 => 9534, 10595 => 9535, + 10596 => 9536, 10597 => 9537, 10598 => 9538, 10599 => 9539, 10600 => 9540, + 10601 => 9541, 10602 => 9542, 10603 => 9543, 10604 => 9544, 10605 => 9545, + 10606 => 9546, 10607 => 9547, 12321 => 21834, 12322 => 38463, 12323 => 22467, + 12324 => 25384, 12325 => 21710, 12326 => 21769, 12327 => 21696, 12328 => 30353, + 12329 => 30284, 12330 => 34108, 12331 => 30702, 12332 => 33406, 12333 => 30861, + 12334 => 29233, 12335 => 38552, 12336 => 38797, 12337 => 27688, 12338 => 23433, + 12339 => 20474, 12340 => 25353, 12341 => 26263, 12342 => 23736, 12343 => 33018, + 12344 => 26696, 12345 => 32942, 12346 => 26114, 12347 => 30414, 12348 => 20985, + 12349 => 25942, 12350 => 29100, 12351 => 32753, 12352 => 34948, 12353 => 20658, + 12354 => 22885, 12355 => 25034, 12356 => 28595, 12357 => 33453, 12358 => 25420, + 12359 => 25170, 12360 => 21485, 12361 => 21543, 12362 => 31494, 12363 => 20843, + 12364 => 30116, 12365 => 24052, 12366 => 25300, 12367 => 36299, 12368 => 38774, + 12369 => 25226, 12370 => 32793, 12371 => 22365, 12372 => 38712, 12373 => 32610, + 12374 => 29240, 12375 => 30333, 12376 => 26575, 12377 => 30334, 12378 => 25670, + 12379 => 20336, 12380 => 36133, 12381 => 25308, 12382 => 31255, 12383 => 26001, + 12384 => 29677, 12385 => 25644, 12386 => 25203, 12387 => 33324, 12388 => 39041, + 12389 => 26495, 12390 => 29256, 12391 => 25198, 12392 => 25292, 12393 => 20276, + 12394 => 29923, 12395 => 21322, 12396 => 21150, 12397 => 32458, 12398 => 37030, + 12399 => 24110, 12400 => 26758, 12401 => 27036, 12402 => 33152, 12403 => 32465, + 12404 => 26834, 12405 => 30917, 12406 => 34444, 12407 => 38225, 12408 => 20621, + 12409 => 35876, 12410 => 33502, 12411 => 32990, 12412 => 21253, 12413 => 35090, + 12414 => 21093, 12577 => 34180, 12578 => 38649, 12579 => 20445, 12580 => 22561, + 12581 => 39281, 12582 => 23453, 12583 => 25265, 12584 => 25253, 12585 => 26292, + 12586 => 35961, 12587 => 40077, 12588 => 29190, 12589 => 26479, 12590 => 30865, + 12591 => 24754, 12592 => 21329, 12593 => 21271, 12594 => 36744, 12595 => 32972, + 12596 => 36125, 12597 => 38049, 12598 => 20493, 12599 => 29384, 12600 => 22791, + 12601 => 24811, 12602 => 28953, 12603 => 34987, 12604 => 22868, 12605 => 33519, + 12606 => 26412, 12607 => 31528, 12608 => 23849, 12609 => 32503, 12610 => 29997, + 12611 => 27893, 12612 => 36454, 12613 => 36856, 12614 => 36924, 12615 => 40763, + 12616 => 27604, 12617 => 37145, 12618 => 31508, 12619 => 24444, 12620 => 30887, + 12621 => 34006, 12622 => 34109, 12623 => 27605, 12624 => 27609, 12625 => 27606, + 12626 => 24065, 12627 => 24199, 12628 => 30201, 12629 => 38381, 12630 => 25949, + 12631 => 24330, 12632 => 24517, 12633 => 36767, 12634 => 22721, 12635 => 33218, + 12636 => 36991, 12637 => 38491, 12638 => 38829, 12639 => 36793, 12640 => 32534, + 12641 => 36140, 12642 => 25153, 12643 => 20415, 12644 => 21464, 12645 => 21342, + 12646 => 36776, 12647 => 36777, 12648 => 36779, 12649 => 36941, 12650 => 26631, + 12651 => 24426, 12652 => 33176, 12653 => 34920, 12654 => 40150, 12655 => 24971, + 12656 => 21035, 12657 => 30250, 12658 => 24428, 12659 => 25996, 12660 => 28626, + 12661 => 28392, 12662 => 23486, 12663 => 25672, 12664 => 20853, 12665 => 20912, + 12666 => 26564, 12667 => 19993, 12668 => 31177, 12669 => 39292, 12670 => 28851, + 12833 => 30149, 12834 => 24182, 12835 => 29627, 12836 => 33760, 12837 => 25773, + 12838 => 25320, 12839 => 38069, 12840 => 27874, 12841 => 21338, 12842 => 21187, + 12843 => 25615, 12844 => 38082, 12845 => 31636, 12846 => 20271, 12847 => 24091, + 12848 => 33334, 12849 => 33046, 12850 => 33162, 12851 => 28196, 12852 => 27850, + 12853 => 39539, 12854 => 25429, 12855 => 21340, 12856 => 21754, 12857 => 34917, + 12858 => 22496, 12859 => 19981, 12860 => 24067, 12861 => 27493, 12862 => 31807, + 12863 => 37096, 12864 => 24598, 12865 => 25830, 12866 => 29468, 12867 => 35009, + 12868 => 26448, 12869 => 25165, 12870 => 36130, 12871 => 30572, 12872 => 36393, + 12873 => 37319, 12874 => 24425, 12875 => 33756, 12876 => 34081, 12877 => 39184, + 12878 => 21442, 12879 => 34453, 12880 => 27531, 12881 => 24813, 12882 => 24808, + 12883 => 28799, 12884 => 33485, 12885 => 33329, 12886 => 20179, 12887 => 27815, + 12888 => 34255, 12889 => 25805, 12890 => 31961, 12891 => 27133, 12892 => 26361, + 12893 => 33609, 12894 => 21397, 12895 => 31574, 12896 => 20391, 12897 => 20876, + 12898 => 27979, 12899 => 23618, 12900 => 36461, 12901 => 25554, 12902 => 21449, + 12903 => 33580, 12904 => 33590, 12905 => 26597, 12906 => 30900, 12907 => 25661, + 12908 => 23519, 12909 => 23700, 12910 => 24046, 12911 => 35815, 12912 => 25286, + 12913 => 26612, 12914 => 35962, 12915 => 25600, 12916 => 25530, 12917 => 34633, + 12918 => 39307, 12919 => 35863, 12920 => 32544, 12921 => 38130, 12922 => 20135, + 12923 => 38416, 12924 => 39076, 12925 => 26124, 12926 => 29462, 13089 => 22330, + 13090 => 23581, 13091 => 24120, 13092 => 38271, 13093 => 20607, 13094 => 32928, + 13095 => 21378, 13096 => 25950, 13097 => 30021, 13098 => 21809, 13099 => 20513, + 13100 => 36229, 13101 => 25220, 13102 => 38046, 13103 => 26397, 13104 => 22066, + 13105 => 28526, 13106 => 24034, 13107 => 21557, 13108 => 28818, 13109 => 36710, + 13110 => 25199, 13111 => 25764, 13112 => 25507, 13113 => 24443, 13114 => 28552, + 13115 => 37108, 13116 => 33251, 13117 => 36784, 13118 => 23576, 13119 => 26216, + 13120 => 24561, 13121 => 27785, 13122 => 38472, 13123 => 36225, 13124 => 34924, + 13125 => 25745, 13126 => 31216, 13127 => 22478, 13128 => 27225, 13129 => 25104, + 13130 => 21576, 13131 => 20056, 13132 => 31243, 13133 => 24809, 13134 => 28548, + 13135 => 35802, 13136 => 25215, 13137 => 36894, 13138 => 39563, 13139 => 31204, + 13140 => 21507, 13141 => 30196, 13142 => 25345, 13143 => 21273, 13144 => 27744, + 13145 => 36831, 13146 => 24347, 13147 => 39536, 13148 => 32827, 13149 => 40831, + 13150 => 20360, 13151 => 23610, 13152 => 36196, 13153 => 32709, 13154 => 26021, + 13155 => 28861, 13156 => 20805, 13157 => 20914, 13158 => 34411, 13159 => 23815, + 13160 => 23456, 13161 => 25277, 13162 => 37228, 13163 => 30068, 13164 => 36364, + 13165 => 31264, 13166 => 24833, 13167 => 31609, 13168 => 20167, 13169 => 32504, + 13170 => 30597, 13171 => 19985, 13172 => 33261, 13173 => 21021, 13174 => 20986, + 13175 => 27249, 13176 => 21416, 13177 => 36487, 13178 => 38148, 13179 => 38607, + 13180 => 28353, 13181 => 38500, 13182 => 26970, 13345 => 30784, 13346 => 20648, + 13347 => 30679, 13348 => 25616, 13349 => 35302, 13350 => 22788, 13351 => 25571, + 13352 => 24029, 13353 => 31359, 13354 => 26941, 13355 => 20256, 13356 => 33337, + 13357 => 21912, 13358 => 20018, 13359 => 30126, 13360 => 31383, 13361 => 24162, + 13362 => 24202, 13363 => 38383, 13364 => 21019, 13365 => 21561, 13366 => 28810, + 13367 => 25462, 13368 => 38180, 13369 => 22402, 13370 => 26149, 13371 => 26943, + 13372 => 37255, 13373 => 21767, 13374 => 28147, 13375 => 32431, 13376 => 34850, + 13377 => 25139, 13378 => 32496, 13379 => 30133, 13380 => 33576, 13381 => 30913, + 13382 => 38604, 13383 => 36766, 13384 => 24904, 13385 => 29943, 13386 => 35789, + 13387 => 27492, 13388 => 21050, 13389 => 36176, 13390 => 27425, 13391 => 32874, + 13392 => 33905, 13393 => 22257, 13394 => 21254, 13395 => 20174, 13396 => 19995, + 13397 => 20945, 13398 => 31895, 13399 => 37259, 13400 => 31751, 13401 => 20419, + 13402 => 36479, 13403 => 31713, 13404 => 31388, 13405 => 25703, 13406 => 23828, + 13407 => 20652, 13408 => 33030, 13409 => 30209, 13410 => 31929, 13411 => 28140, + 13412 => 32736, 13413 => 26449, 13414 => 23384, 13415 => 23544, 13416 => 30923, + 13417 => 25774, 13418 => 25619, 13419 => 25514, 13420 => 25387, 13421 => 38169, + 13422 => 25645, 13423 => 36798, 13424 => 31572, 13425 => 30249, 13426 => 25171, + 13427 => 22823, 13428 => 21574, 13429 => 27513, 13430 => 20643, 13431 => 25140, + 13432 => 24102, 13433 => 27526, 13434 => 20195, 13435 => 36151, 13436 => 34955, + 13437 => 24453, 13438 => 36910, 13601 => 24608, 13602 => 32829, 13603 => 25285, + 13604 => 20025, 13605 => 21333, 13606 => 37112, 13607 => 25528, 13608 => 32966, + 13609 => 26086, 13610 => 27694, 13611 => 20294, 13612 => 24814, 13613 => 28129, + 13614 => 35806, 13615 => 24377, 13616 => 34507, 13617 => 24403, 13618 => 25377, + 13619 => 20826, 13620 => 33633, 13621 => 26723, 13622 => 20992, 13623 => 25443, + 13624 => 36424, 13625 => 20498, 13626 => 23707, 13627 => 31095, 13628 => 23548, + 13629 => 21040, 13630 => 31291, 13631 => 24764, 13632 => 36947, 13633 => 30423, + 13634 => 24503, 13635 => 24471, 13636 => 30340, 13637 => 36460, 13638 => 28783, + 13639 => 30331, 13640 => 31561, 13641 => 30634, 13642 => 20979, 13643 => 37011, + 13644 => 22564, 13645 => 20302, 13646 => 28404, 13647 => 36842, 13648 => 25932, + 13649 => 31515, 13650 => 29380, 13651 => 28068, 13652 => 32735, 13653 => 23265, + 13654 => 25269, 13655 => 24213, 13656 => 22320, 13657 => 33922, 13658 => 31532, + 13659 => 24093, 13660 => 24351, 13661 => 36882, 13662 => 32532, 13663 => 39072, + 13664 => 25474, 13665 => 28359, 13666 => 30872, 13667 => 28857, 13668 => 20856, + 13669 => 38747, 13670 => 22443, 13671 => 30005, 13672 => 20291, 13673 => 30008, + 13674 => 24215, 13675 => 24806, 13676 => 22880, 13677 => 28096, 13678 => 27583, + 13679 => 30857, 13680 => 21500, 13681 => 38613, 13682 => 20939, 13683 => 20993, + 13684 => 25481, 13685 => 21514, 13686 => 38035, 13687 => 35843, 13688 => 36300, + 13689 => 29241, 13690 => 30879, 13691 => 34678, 13692 => 36845, 13693 => 35853, + 13694 => 21472, 13857 => 19969, 13858 => 30447, 13859 => 21486, 13860 => 38025, + 13861 => 39030, 13862 => 40718, 13863 => 38189, 13864 => 23450, 13865 => 35746, + 13866 => 20002, 13867 => 19996, 13868 => 20908, 13869 => 33891, 13870 => 25026, + 13871 => 21160, 13872 => 26635, 13873 => 20375, 13874 => 24683, 13875 => 20923, + 13876 => 27934, 13877 => 20828, 13878 => 25238, 13879 => 26007, 13880 => 38497, + 13881 => 35910, 13882 => 36887, 13883 => 30168, 13884 => 37117, 13885 => 30563, + 13886 => 27602, 13887 => 29322, 13888 => 29420, 13889 => 35835, 13890 => 22581, + 13891 => 30585, 13892 => 36172, 13893 => 26460, 13894 => 38208, 13895 => 32922, + 13896 => 24230, 13897 => 28193, 13898 => 22930, 13899 => 31471, 13900 => 30701, + 13901 => 38203, 13902 => 27573, 13903 => 26029, 13904 => 32526, 13905 => 22534, + 13906 => 20817, 13907 => 38431, 13908 => 23545, 13909 => 22697, 13910 => 21544, + 13911 => 36466, 13912 => 25958, 13913 => 39039, 13914 => 22244, 13915 => 38045, + 13916 => 30462, 13917 => 36929, 13918 => 25479, 13919 => 21702, 13920 => 22810, + 13921 => 22842, 13922 => 22427, 13923 => 36530, 13924 => 26421, 13925 => 36346, + 13926 => 33333, 13927 => 21057, 13928 => 24816, 13929 => 22549, 13930 => 34558, + 13931 => 23784, 13932 => 40517, 13933 => 20420, 13934 => 39069, 13935 => 35769, + 13936 => 23077, 13937 => 24694, 13938 => 21380, 13939 => 25212, 13940 => 36943, + 13941 => 37122, 13942 => 39295, 13943 => 24681, 13944 => 32780, 13945 => 20799, + 13946 => 32819, 13947 => 23572, 13948 => 39285, 13949 => 27953, 13950 => 20108, + 14113 => 36144, 14114 => 21457, 14115 => 32602, 14116 => 31567, 14117 => 20240, + 14118 => 20047, 14119 => 38400, 14120 => 27861, 14121 => 29648, 14122 => 34281, + 14123 => 24070, 14124 => 30058, 14125 => 32763, 14126 => 27146, 14127 => 30718, + 14128 => 38034, 14129 => 32321, 14130 => 20961, 14131 => 28902, 14132 => 21453, + 14133 => 36820, 14134 => 33539, 14135 => 36137, 14136 => 29359, 14137 => 39277, + 14138 => 27867, 14139 => 22346, 14140 => 33459, 14141 => 26041, 14142 => 32938, + 14143 => 25151, 14144 => 38450, 14145 => 22952, 14146 => 20223, 14147 => 35775, + 14148 => 32442, 14149 => 25918, 14150 => 33778, 14151 => 38750, 14152 => 21857, + 14153 => 39134, 14154 => 32933, 14155 => 21290, 14156 => 35837, 14157 => 21536, + 14158 => 32954, 14159 => 24223, 14160 => 27832, 14161 => 36153, 14162 => 33452, + 14163 => 37210, 14164 => 21545, 14165 => 27675, 14166 => 20998, 14167 => 32439, + 14168 => 22367, 14169 => 28954, 14170 => 27774, 14171 => 31881, 14172 => 22859, + 14173 => 20221, 14174 => 24575, 14175 => 24868, 14176 => 31914, 14177 => 20016, + 14178 => 23553, 14179 => 26539, 14180 => 34562, 14181 => 23792, 14182 => 38155, + 14183 => 39118, 14184 => 30127, 14185 => 28925, 14186 => 36898, 14187 => 20911, + 14188 => 32541, 14189 => 35773, 14190 => 22857, 14191 => 20964, 14192 => 20315, + 14193 => 21542, 14194 => 22827, 14195 => 25975, 14196 => 32932, 14197 => 23413, + 14198 => 25206, 14199 => 25282, 14200 => 36752, 14201 => 24133, 14202 => 27679, + 14203 => 31526, 14204 => 20239, 14205 => 20440, 14206 => 26381, 14369 => 28014, + 14370 => 28074, 14371 => 31119, 14372 => 34993, 14373 => 24343, 14374 => 29995, + 14375 => 25242, 14376 => 36741, 14377 => 20463, 14378 => 37340, 14379 => 26023, + 14380 => 33071, 14381 => 33105, 14382 => 24220, 14383 => 33104, 14384 => 36212, + 14385 => 21103, 14386 => 35206, 14387 => 36171, 14388 => 22797, 14389 => 20613, + 14390 => 20184, 14391 => 38428, 14392 => 29238, 14393 => 33145, 14394 => 36127, + 14395 => 23500, 14396 => 35747, 14397 => 38468, 14398 => 22919, 14399 => 32538, + 14400 => 21648, 14401 => 22134, 14402 => 22030, 14403 => 35813, 14404 => 25913, + 14405 => 27010, 14406 => 38041, 14407 => 30422, 14408 => 28297, 14409 => 24178, + 14410 => 29976, 14411 => 26438, 14412 => 26577, 14413 => 31487, 14414 => 32925, + 14415 => 36214, 14416 => 24863, 14417 => 31174, 14418 => 25954, 14419 => 36195, + 14420 => 20872, 14421 => 21018, 14422 => 38050, 14423 => 32568, 14424 => 32923, + 14425 => 32434, 14426 => 23703, 14427 => 28207, 14428 => 26464, 14429 => 31705, + 14430 => 30347, 14431 => 39640, 14432 => 33167, 14433 => 32660, 14434 => 31957, + 14435 => 25630, 14436 => 38224, 14437 => 31295, 14438 => 21578, 14439 => 21733, + 14440 => 27468, 14441 => 25601, 14442 => 25096, 14443 => 40509, 14444 => 33011, + 14445 => 30105, 14446 => 21106, 14447 => 38761, 14448 => 33883, 14449 => 26684, + 14450 => 34532, 14451 => 38401, 14452 => 38548, 14453 => 38124, 14454 => 20010, + 14455 => 21508, 14456 => 32473, 14457 => 26681, 14458 => 36319, 14459 => 32789, + 14460 => 26356, 14461 => 24218, 14462 => 32697, 14625 => 22466, 14626 => 32831, + 14627 => 26775, 14628 => 24037, 14629 => 25915, 14630 => 21151, 14631 => 24685, + 14632 => 40858, 14633 => 20379, 14634 => 36524, 14635 => 20844, 14636 => 23467, + 14637 => 24339, 14638 => 24041, 14639 => 27742, 14640 => 25329, 14641 => 36129, + 14642 => 20849, 14643 => 38057, 14644 => 21246, 14645 => 27807, 14646 => 33503, + 14647 => 29399, 14648 => 22434, 14649 => 26500, 14650 => 36141, 14651 => 22815, + 14652 => 36764, 14653 => 33735, 14654 => 21653, 14655 => 31629, 14656 => 20272, + 14657 => 27837, 14658 => 23396, 14659 => 22993, 14660 => 40723, 14661 => 21476, + 14662 => 34506, 14663 => 39592, 14664 => 35895, 14665 => 32929, 14666 => 25925, + 14667 => 39038, 14668 => 22266, 14669 => 38599, 14670 => 21038, 14671 => 29916, + 14672 => 21072, 14673 => 23521, 14674 => 25346, 14675 => 35074, 14676 => 20054, + 14677 => 25296, 14678 => 24618, 14679 => 26874, 14680 => 20851, 14681 => 23448, + 14682 => 20896, 14683 => 35266, 14684 => 31649, 14685 => 39302, 14686 => 32592, + 14687 => 24815, 14688 => 28748, 14689 => 36143, 14690 => 20809, 14691 => 24191, + 14692 => 36891, 14693 => 29808, 14694 => 35268, 14695 => 22317, 14696 => 30789, + 14697 => 24402, 14698 => 40863, 14699 => 38394, 14700 => 36712, 14701 => 39740, + 14702 => 35809, 14703 => 30328, 14704 => 26690, 14705 => 26588, 14706 => 36330, + 14707 => 36149, 14708 => 21053, 14709 => 36746, 14710 => 28378, 14711 => 26829, + 14712 => 38149, 14713 => 37101, 14714 => 22269, 14715 => 26524, 14716 => 35065, + 14717 => 36807, 14718 => 21704, 14881 => 39608, 14882 => 23401, 14883 => 28023, + 14884 => 27686, 14885 => 20133, 14886 => 23475, 14887 => 39559, 14888 => 37219, + 14889 => 25000, 14890 => 37039, 14891 => 38889, 14892 => 21547, 14893 => 28085, + 14894 => 23506, 14895 => 20989, 14896 => 21898, 14897 => 32597, 14898 => 32752, + 14899 => 25788, 14900 => 25421, 14901 => 26097, 14902 => 25022, 14903 => 24717, + 14904 => 28938, 14905 => 27735, 14906 => 27721, 14907 => 22831, 14908 => 26477, + 14909 => 33322, 14910 => 22741, 14911 => 22158, 14912 => 35946, 14913 => 27627, + 14914 => 37085, 14915 => 22909, 14916 => 32791, 14917 => 21495, 14918 => 28009, + 14919 => 21621, 14920 => 21917, 14921 => 33655, 14922 => 33743, 14923 => 26680, + 14924 => 31166, 14925 => 21644, 14926 => 20309, 14927 => 21512, 14928 => 30418, + 14929 => 35977, 14930 => 38402, 14931 => 27827, 14932 => 28088, 14933 => 36203, + 14934 => 35088, 14935 => 40548, 14936 => 36154, 14937 => 22079, 14938 => 40657, + 14939 => 30165, 14940 => 24456, 14941 => 29408, 14942 => 24680, 14943 => 21756, + 14944 => 20136, 14945 => 27178, 14946 => 34913, 14947 => 24658, 14948 => 36720, + 14949 => 21700, 14950 => 28888, 14951 => 34425, 14952 => 40511, 14953 => 27946, + 14954 => 23439, 14955 => 24344, 14956 => 32418, 14957 => 21897, 14958 => 20399, + 14959 => 29492, 14960 => 21564, 14961 => 21402, 14962 => 20505, 14963 => 21518, + 14964 => 21628, 14965 => 20046, 14966 => 24573, 14967 => 29786, 14968 => 22774, + 14969 => 33899, 14970 => 32993, 14971 => 34676, 14972 => 29392, 14973 => 31946, + 14974 => 28246, 15137 => 24359, 15138 => 34382, 15139 => 21804, 15140 => 25252, + 15141 => 20114, 15142 => 27818, 15143 => 25143, 15144 => 33457, 15145 => 21719, + 15146 => 21326, 15147 => 29502, 15148 => 28369, 15149 => 30011, 15150 => 21010, + 15151 => 21270, 15152 => 35805, 15153 => 27088, 15154 => 24458, 15155 => 24576, + 15156 => 28142, 15157 => 22351, 15158 => 27426, 15159 => 29615, 15160 => 26707, + 15161 => 36824, 15162 => 32531, 15163 => 25442, 15164 => 24739, 15165 => 21796, + 15166 => 30186, 15167 => 35938, 15168 => 28949, 15169 => 28067, 15170 => 23462, + 15171 => 24187, 15172 => 33618, 15173 => 24908, 15174 => 40644, 15175 => 30970, + 15176 => 34647, 15177 => 31783, 15178 => 30343, 15179 => 20976, 15180 => 24822, + 15181 => 29004, 15182 => 26179, 15183 => 24140, 15184 => 24653, 15185 => 35854, + 15186 => 28784, 15187 => 25381, 15188 => 36745, 15189 => 24509, 15190 => 24674, + 15191 => 34516, 15192 => 22238, 15193 => 27585, 15194 => 24724, 15195 => 24935, + 15196 => 21321, 15197 => 24800, 15198 => 26214, 15199 => 36159, 15200 => 31229, + 15201 => 20250, 15202 => 28905, 15203 => 27719, 15204 => 35763, 15205 => 35826, + 15206 => 32472, 15207 => 33636, 15208 => 26127, 15209 => 23130, 15210 => 39746, + 15211 => 27985, 15212 => 28151, 15213 => 35905, 15214 => 27963, 15215 => 20249, + 15216 => 28779, 15217 => 33719, 15218 => 25110, 15219 => 24785, 15220 => 38669, + 15221 => 36135, 15222 => 31096, 15223 => 20987, 15224 => 22334, 15225 => 22522, + 15226 => 26426, 15227 => 30072, 15228 => 31293, 15229 => 31215, 15230 => 31637, + 15393 => 32908, 15394 => 39269, 15395 => 36857, 15396 => 28608, 15397 => 35749, + 15398 => 40481, 15399 => 23020, 15400 => 32489, 15401 => 32521, 15402 => 21513, + 15403 => 26497, 15404 => 26840, 15405 => 36753, 15406 => 31821, 15407 => 38598, + 15408 => 21450, 15409 => 24613, 15410 => 30142, 15411 => 27762, 15412 => 21363, + 15413 => 23241, 15414 => 32423, 15415 => 25380, 15416 => 20960, 15417 => 33034, + 15418 => 24049, 15419 => 34015, 15420 => 25216, 15421 => 20864, 15422 => 23395, + 15423 => 20238, 15424 => 31085, 15425 => 21058, 15426 => 24760, 15427 => 27982, + 15428 => 23492, 15429 => 23490, 15430 => 35745, 15431 => 35760, 15432 => 26082, + 15433 => 24524, 15434 => 38469, 15435 => 22931, 15436 => 32487, 15437 => 32426, + 15438 => 22025, 15439 => 26551, 15440 => 22841, 15441 => 20339, 15442 => 23478, + 15443 => 21152, 15444 => 33626, 15445 => 39050, 15446 => 36158, 15447 => 30002, + 15448 => 38078, 15449 => 20551, 15450 => 31292, 15451 => 20215, 15452 => 26550, + 15453 => 39550, 15454 => 23233, 15455 => 27516, 15456 => 30417, 15457 => 22362, + 15458 => 23574, 15459 => 31546, 15460 => 38388, 15461 => 29006, 15462 => 20860, + 15463 => 32937, 15464 => 33392, 15465 => 22904, 15466 => 32516, 15467 => 33575, + 15468 => 26816, 15469 => 26604, 15470 => 30897, 15471 => 30839, 15472 => 25315, + 15473 => 25441, 15474 => 31616, 15475 => 20461, 15476 => 21098, 15477 => 20943, + 15478 => 33616, 15479 => 27099, 15480 => 37492, 15481 => 36341, 15482 => 36145, + 15483 => 35265, 15484 => 38190, 15485 => 31661, 15486 => 20214, 15649 => 20581, + 15650 => 33328, 15651 => 21073, 15652 => 39279, 15653 => 28176, 15654 => 28293, + 15655 => 28071, 15656 => 24314, 15657 => 20725, 15658 => 23004, 15659 => 23558, + 15660 => 27974, 15661 => 27743, 15662 => 30086, 15663 => 33931, 15664 => 26728, + 15665 => 22870, 15666 => 35762, 15667 => 21280, 15668 => 37233, 15669 => 38477, + 15670 => 34121, 15671 => 26898, 15672 => 30977, 15673 => 28966, 15674 => 33014, + 15675 => 20132, 15676 => 37066, 15677 => 27975, 15678 => 39556, 15679 => 23047, + 15680 => 22204, 15681 => 25605, 15682 => 38128, 15683 => 30699, 15684 => 20389, + 15685 => 33050, 15686 => 29409, 15687 => 35282, 15688 => 39290, 15689 => 32564, + 15690 => 32478, 15691 => 21119, 15692 => 25945, 15693 => 37237, 15694 => 36735, + 15695 => 36739, 15696 => 21483, 15697 => 31382, 15698 => 25581, 15699 => 25509, + 15700 => 30342, 15701 => 31224, 15702 => 34903, 15703 => 38454, 15704 => 25130, + 15705 => 21163, 15706 => 33410, 15707 => 26708, 15708 => 26480, 15709 => 25463, + 15710 => 30571, 15711 => 31469, 15712 => 27905, 15713 => 32467, 15714 => 35299, + 15715 => 22992, 15716 => 25106, 15717 => 34249, 15718 => 33445, 15719 => 30028, + 15720 => 20511, 15721 => 20171, 15722 => 30117, 15723 => 35819, 15724 => 23626, + 15725 => 24062, 15726 => 31563, 15727 => 26020, 15728 => 37329, 15729 => 20170, + 15730 => 27941, 15731 => 35167, 15732 => 32039, 15733 => 38182, 15734 => 20165, + 15735 => 35880, 15736 => 36827, 15737 => 38771, 15738 => 26187, 15739 => 31105, + 15740 => 36817, 15741 => 28908, 15742 => 28024, 15905 => 23613, 15906 => 21170, + 15907 => 33606, 15908 => 20834, 15909 => 33550, 15910 => 30555, 15911 => 26230, + 15912 => 40120, 15913 => 20140, 15914 => 24778, 15915 => 31934, 15916 => 31923, + 15917 => 32463, 15918 => 20117, 15919 => 35686, 15920 => 26223, 15921 => 39048, + 15922 => 38745, 15923 => 22659, 15924 => 25964, 15925 => 38236, 15926 => 24452, + 15927 => 30153, 15928 => 38742, 15929 => 31455, 15930 => 31454, 15931 => 20928, + 15932 => 28847, 15933 => 31384, 15934 => 25578, 15935 => 31350, 15936 => 32416, + 15937 => 29590, 15938 => 38893, 15939 => 20037, 15940 => 28792, 15941 => 20061, + 15942 => 37202, 15943 => 21417, 15944 => 25937, 15945 => 26087, 15946 => 33276, + 15947 => 33285, 15948 => 21646, 15949 => 23601, 15950 => 30106, 15951 => 38816, + 15952 => 25304, 15953 => 29401, 15954 => 30141, 15955 => 23621, 15956 => 39545, + 15957 => 33738, 15958 => 23616, 15959 => 21632, 15960 => 30697, 15961 => 20030, + 15962 => 27822, 15963 => 32858, 15964 => 25298, 15965 => 25454, 15966 => 24040, + 15967 => 20855, 15968 => 36317, 15969 => 36382, 15970 => 38191, 15971 => 20465, + 15972 => 21477, 15973 => 24807, 15974 => 28844, 15975 => 21095, 15976 => 25424, + 15977 => 40515, 15978 => 23071, 15979 => 20518, 15980 => 30519, 15981 => 21367, + 15982 => 32482, 15983 => 25733, 15984 => 25899, 15985 => 25225, 15986 => 25496, + 15987 => 20500, 15988 => 29237, 15989 => 35273, 15990 => 20915, 15991 => 35776, + 15992 => 32477, 15993 => 22343, 15994 => 33740, 15995 => 38055, 15996 => 20891, + 15997 => 21531, 15998 => 23803, 16161 => 20426, 16162 => 31459, 16163 => 27994, + 16164 => 37089, 16165 => 39567, 16166 => 21888, 16167 => 21654, 16168 => 21345, + 16169 => 21679, 16170 => 24320, 16171 => 25577, 16172 => 26999, 16173 => 20975, + 16174 => 24936, 16175 => 21002, 16176 => 22570, 16177 => 21208, 16178 => 22350, + 16179 => 30733, 16180 => 30475, 16181 => 24247, 16182 => 24951, 16183 => 31968, + 16184 => 25179, 16185 => 25239, 16186 => 20130, 16187 => 28821, 16188 => 32771, + 16189 => 25335, 16190 => 28900, 16191 => 38752, 16192 => 22391, 16193 => 33499, + 16194 => 26607, 16195 => 26869, 16196 => 30933, 16197 => 39063, 16198 => 31185, + 16199 => 22771, 16200 => 21683, 16201 => 21487, 16202 => 28212, 16203 => 20811, + 16204 => 21051, 16205 => 23458, 16206 => 35838, 16207 => 32943, 16208 => 21827, + 16209 => 22438, 16210 => 24691, 16211 => 22353, 16212 => 21549, 16213 => 31354, + 16214 => 24656, 16215 => 23380, 16216 => 25511, 16217 => 25248, 16218 => 21475, + 16219 => 25187, 16220 => 23495, 16221 => 26543, 16222 => 21741, 16223 => 31391, + 16224 => 33510, 16225 => 37239, 16226 => 24211, 16227 => 35044, 16228 => 22840, + 16229 => 22446, 16230 => 25358, 16231 => 36328, 16232 => 33007, 16233 => 22359, + 16234 => 31607, 16235 => 20393, 16236 => 24555, 16237 => 23485, 16238 => 27454, + 16239 => 21281, 16240 => 31568, 16241 => 29378, 16242 => 26694, 16243 => 30719, + 16244 => 30518, 16245 => 26103, 16246 => 20917, 16247 => 20111, 16248 => 30420, + 16249 => 23743, 16250 => 31397, 16251 => 33909, 16252 => 22862, 16253 => 39745, + 16254 => 20608, 16417 => 39304, 16418 => 24871, 16419 => 28291, 16420 => 22372, + 16421 => 26118, 16422 => 25414, 16423 => 22256, 16424 => 25324, 16425 => 25193, + 16426 => 24275, 16427 => 38420, 16428 => 22403, 16429 => 25289, 16430 => 21895, + 16431 => 34593, 16432 => 33098, 16433 => 36771, 16434 => 21862, 16435 => 33713, + 16436 => 26469, 16437 => 36182, 16438 => 34013, 16439 => 23146, 16440 => 26639, + 16441 => 25318, 16442 => 31726, 16443 => 38417, 16444 => 20848, 16445 => 28572, + 16446 => 35888, 16447 => 25597, 16448 => 35272, 16449 => 25042, 16450 => 32518, + 16451 => 28866, 16452 => 28389, 16453 => 29701, 16454 => 27028, 16455 => 29436, + 16456 => 24266, 16457 => 37070, 16458 => 26391, 16459 => 28010, 16460 => 25438, + 16461 => 21171, 16462 => 29282, 16463 => 32769, 16464 => 20332, 16465 => 23013, + 16466 => 37226, 16467 => 28889, 16468 => 28061, 16469 => 21202, 16470 => 20048, + 16471 => 38647, 16472 => 38253, 16473 => 34174, 16474 => 30922, 16475 => 32047, + 16476 => 20769, 16477 => 22418, 16478 => 25794, 16479 => 32907, 16480 => 31867, + 16481 => 27882, 16482 => 26865, 16483 => 26974, 16484 => 20919, 16485 => 21400, + 16486 => 26792, 16487 => 29313, 16488 => 40654, 16489 => 31729, 16490 => 29432, + 16491 => 31163, 16492 => 28435, 16493 => 29702, 16494 => 26446, 16495 => 37324, + 16496 => 40100, 16497 => 31036, 16498 => 33673, 16499 => 33620, 16500 => 21519, + 16501 => 26647, 16502 => 20029, 16503 => 21385, 16504 => 21169, 16505 => 30782, + 16506 => 21382, 16507 => 21033, 16508 => 20616, 16509 => 20363, 16510 => 20432, + 16673 => 30178, 16674 => 31435, 16675 => 31890, 16676 => 27813, 16677 => 38582, + 16678 => 21147, 16679 => 29827, 16680 => 21737, 16681 => 20457, 16682 => 32852, + 16683 => 33714, 16684 => 36830, 16685 => 38256, 16686 => 24265, 16687 => 24604, + 16688 => 28063, 16689 => 24088, 16690 => 25947, 16691 => 33080, 16692 => 38142, + 16693 => 24651, 16694 => 28860, 16695 => 32451, 16696 => 31918, 16697 => 20937, + 16698 => 26753, 16699 => 31921, 16700 => 33391, 16701 => 20004, 16702 => 36742, + 16703 => 37327, 16704 => 26238, 16705 => 20142, 16706 => 35845, 16707 => 25769, + 16708 => 32842, 16709 => 20698, 16710 => 30103, 16711 => 29134, 16712 => 23525, + 16713 => 36797, 16714 => 28518, 16715 => 20102, 16716 => 25730, 16717 => 38243, + 16718 => 24278, 16719 => 26009, 16720 => 21015, 16721 => 35010, 16722 => 28872, + 16723 => 21155, 16724 => 29454, 16725 => 29747, 16726 => 26519, 16727 => 30967, + 16728 => 38678, 16729 => 20020, 16730 => 37051, 16731 => 40158, 16732 => 28107, + 16733 => 20955, 16734 => 36161, 16735 => 21533, 16736 => 25294, 16737 => 29618, + 16738 => 33777, 16739 => 38646, 16740 => 40836, 16741 => 38083, 16742 => 20278, + 16743 => 32666, 16744 => 20940, 16745 => 28789, 16746 => 38517, 16747 => 23725, + 16748 => 39046, 16749 => 21478, 16750 => 20196, 16751 => 28316, 16752 => 29705, + 16753 => 27060, 16754 => 30827, 16755 => 39311, 16756 => 30041, 16757 => 21016, + 16758 => 30244, 16759 => 27969, 16760 => 26611, 16761 => 20845, 16762 => 40857, + 16763 => 32843, 16764 => 21657, 16765 => 31548, 16766 => 31423, 16929 => 38534, + 16930 => 22404, 16931 => 25314, 16932 => 38471, 16933 => 27004, 16934 => 23044, + 16935 => 25602, 16936 => 31699, 16937 => 28431, 16938 => 38475, 16939 => 33446, + 16940 => 21346, 16941 => 39045, 16942 => 24208, 16943 => 28809, 16944 => 25523, + 16945 => 21348, 16946 => 34383, 16947 => 40065, 16948 => 40595, 16949 => 30860, + 16950 => 38706, 16951 => 36335, 16952 => 36162, 16953 => 40575, 16954 => 28510, + 16955 => 31108, 16956 => 24405, 16957 => 38470, 16958 => 25134, 16959 => 39540, + 16960 => 21525, 16961 => 38109, 16962 => 20387, 16963 => 26053, 16964 => 23653, + 16965 => 23649, 16966 => 32533, 16967 => 34385, 16968 => 27695, 16969 => 24459, + 16970 => 29575, 16971 => 28388, 16972 => 32511, 16973 => 23782, 16974 => 25371, + 16975 => 23402, 16976 => 28390, 16977 => 21365, 16978 => 20081, 16979 => 25504, + 16980 => 30053, 16981 => 25249, 16982 => 36718, 16983 => 20262, 16984 => 20177, + 16985 => 27814, 16986 => 32438, 16987 => 35770, 16988 => 33821, 16989 => 34746, + 16990 => 32599, 16991 => 36923, 16992 => 38179, 16993 => 31657, 16994 => 39585, + 16995 => 35064, 16996 => 33853, 16997 => 27931, 16998 => 39558, 16999 => 32476, + 17000 => 22920, 17001 => 40635, 17002 => 29595, 17003 => 30721, 17004 => 34434, + 17005 => 39532, 17006 => 39554, 17007 => 22043, 17008 => 21527, 17009 => 22475, + 17010 => 20080, 17011 => 40614, 17012 => 21334, 17013 => 36808, 17014 => 33033, + 17015 => 30610, 17016 => 39314, 17017 => 34542, 17018 => 28385, 17019 => 34067, + 17020 => 26364, 17021 => 24930, 17022 => 28459, 17185 => 35881, 17186 => 33426, + 17187 => 33579, 17188 => 30450, 17189 => 27667, 17190 => 24537, 17191 => 33725, + 17192 => 29483, 17193 => 33541, 17194 => 38170, 17195 => 27611, 17196 => 30683, + 17197 => 38086, 17198 => 21359, 17199 => 33538, 17200 => 20882, 17201 => 24125, + 17202 => 35980, 17203 => 36152, 17204 => 20040, 17205 => 29611, 17206 => 26522, + 17207 => 26757, 17208 => 37238, 17209 => 38665, 17210 => 29028, 17211 => 27809, + 17212 => 30473, 17213 => 23186, 17214 => 38209, 17215 => 27599, 17216 => 32654, + 17217 => 26151, 17218 => 23504, 17219 => 22969, 17220 => 23194, 17221 => 38376, + 17222 => 38391, 17223 => 20204, 17224 => 33804, 17225 => 33945, 17226 => 27308, + 17227 => 30431, 17228 => 38192, 17229 => 29467, 17230 => 26790, 17231 => 23391, + 17232 => 30511, 17233 => 37274, 17234 => 38753, 17235 => 31964, 17236 => 36855, + 17237 => 35868, 17238 => 24357, 17239 => 31859, 17240 => 31192, 17241 => 35269, + 17242 => 27852, 17243 => 34588, 17244 => 23494, 17245 => 24130, 17246 => 26825, + 17247 => 30496, 17248 => 32501, 17249 => 20885, 17250 => 20813, 17251 => 21193, + 17252 => 23081, 17253 => 32517, 17254 => 38754, 17255 => 33495, 17256 => 25551, + 17257 => 30596, 17258 => 34256, 17259 => 31186, 17260 => 28218, 17261 => 24217, + 17262 => 22937, 17263 => 34065, 17264 => 28781, 17265 => 27665, 17266 => 25279, + 17267 => 30399, 17268 => 25935, 17269 => 24751, 17270 => 38397, 17271 => 26126, + 17272 => 34719, 17273 => 40483, 17274 => 38125, 17275 => 21517, 17276 => 21629, + 17277 => 35884, 17278 => 25720, 17441 => 25721, 17442 => 34321, 17443 => 27169, + 17444 => 33180, 17445 => 30952, 17446 => 25705, 17447 => 39764, 17448 => 25273, + 17449 => 26411, 17450 => 33707, 17451 => 22696, 17452 => 40664, 17453 => 27819, + 17454 => 28448, 17455 => 23518, 17456 => 38476, 17457 => 35851, 17458 => 29279, + 17459 => 26576, 17460 => 25287, 17461 => 29281, 17462 => 20137, 17463 => 22982, + 17464 => 27597, 17465 => 22675, 17466 => 26286, 17467 => 24149, 17468 => 21215, + 17469 => 24917, 17470 => 26408, 17471 => 30446, 17472 => 30566, 17473 => 29287, + 17474 => 31302, 17475 => 25343, 17476 => 21738, 17477 => 21584, 17478 => 38048, + 17479 => 37027, 17480 => 23068, 17481 => 32435, 17482 => 27670, 17483 => 20035, + 17484 => 22902, 17485 => 32784, 17486 => 22856, 17487 => 21335, 17488 => 30007, + 17489 => 38590, 17490 => 22218, 17491 => 25376, 17492 => 33041, 17493 => 24700, + 17494 => 38393, 17495 => 28118, 17496 => 21602, 17497 => 39297, 17498 => 20869, + 17499 => 23273, 17500 => 33021, 17501 => 22958, 17502 => 38675, 17503 => 20522, + 17504 => 27877, 17505 => 23612, 17506 => 25311, 17507 => 20320, 17508 => 21311, + 17509 => 33147, 17510 => 36870, 17511 => 28346, 17512 => 34091, 17513 => 25288, + 17514 => 24180, 17515 => 30910, 17516 => 25781, 17517 => 25467, 17518 => 24565, + 17519 => 23064, 17520 => 37247, 17521 => 40479, 17522 => 23615, 17523 => 25423, + 17524 => 32834, 17525 => 23421, 17526 => 21870, 17527 => 38218, 17528 => 38221, + 17529 => 28037, 17530 => 24744, 17531 => 26592, 17532 => 29406, 17533 => 20957, + 17534 => 23425, 17697 => 25319, 17698 => 27870, 17699 => 29275, 17700 => 25197, + 17701 => 38062, 17702 => 32445, 17703 => 33043, 17704 => 27987, 17705 => 20892, + 17706 => 24324, 17707 => 22900, 17708 => 21162, 17709 => 24594, 17710 => 22899, + 17711 => 26262, 17712 => 34384, 17713 => 30111, 17714 => 25386, 17715 => 25062, + 17716 => 31983, 17717 => 35834, 17718 => 21734, 17719 => 27431, 17720 => 40485, + 17721 => 27572, 17722 => 34261, 17723 => 21589, 17724 => 20598, 17725 => 27812, + 17726 => 21866, 17727 => 36276, 17728 => 29228, 17729 => 24085, 17730 => 24597, + 17731 => 29750, 17732 => 25293, 17733 => 25490, 17734 => 29260, 17735 => 24472, + 17736 => 28227, 17737 => 27966, 17738 => 25856, 17739 => 28504, 17740 => 30424, + 17741 => 30928, 17742 => 30460, 17743 => 30036, 17744 => 21028, 17745 => 21467, + 17746 => 20051, 17747 => 24222, 17748 => 26049, 17749 => 32810, 17750 => 32982, + 17751 => 25243, 17752 => 21638, 17753 => 21032, 17754 => 28846, 17755 => 34957, + 17756 => 36305, 17757 => 27873, 17758 => 21624, 17759 => 32986, 17760 => 22521, + 17761 => 35060, 17762 => 36180, 17763 => 38506, 17764 => 37197, 17765 => 20329, + 17766 => 27803, 17767 => 21943, 17768 => 30406, 17769 => 30768, 17770 => 25256, + 17771 => 28921, 17772 => 28558, 17773 => 24429, 17774 => 34028, 17775 => 26842, + 17776 => 30844, 17777 => 31735, 17778 => 33192, 17779 => 26379, 17780 => 40527, + 17781 => 25447, 17782 => 30896, 17783 => 22383, 17784 => 30738, 17785 => 38713, + 17786 => 25209, 17787 => 25259, 17788 => 21128, 17789 => 29749, 17790 => 27607, + 17953 => 21860, 17954 => 33086, 17955 => 30130, 17956 => 30382, 17957 => 21305, + 17958 => 30174, 17959 => 20731, 17960 => 23617, 17961 => 35692, 17962 => 31687, + 17963 => 20559, 17964 => 29255, 17965 => 39575, 17966 => 39128, 17967 => 28418, + 17968 => 29922, 17969 => 31080, 17970 => 25735, 17971 => 30629, 17972 => 25340, + 17973 => 39057, 17974 => 36139, 17975 => 21697, 17976 => 32856, 17977 => 20050, + 17978 => 22378, 17979 => 33529, 17980 => 33805, 17981 => 24179, 17982 => 20973, + 17983 => 29942, 17984 => 35780, 17985 => 23631, 17986 => 22369, 17987 => 27900, + 17988 => 39047, 17989 => 23110, 17990 => 30772, 17991 => 39748, 17992 => 36843, + 17993 => 31893, 17994 => 21078, 17995 => 25169, 17996 => 38138, 17997 => 20166, + 17998 => 33670, 17999 => 33889, 18000 => 33769, 18001 => 33970, 18002 => 22484, + 18003 => 26420, 18004 => 22275, 18005 => 26222, 18006 => 28006, 18007 => 35889, + 18008 => 26333, 18009 => 28689, 18010 => 26399, 18011 => 27450, 18012 => 26646, + 18013 => 25114, 18014 => 22971, 18015 => 19971, 18016 => 20932, 18017 => 28422, + 18018 => 26578, 18019 => 27791, 18020 => 20854, 18021 => 26827, 18022 => 22855, + 18023 => 27495, 18024 => 30054, 18025 => 23822, 18026 => 33040, 18027 => 40784, + 18028 => 26071, 18029 => 31048, 18030 => 31041, 18031 => 39569, 18032 => 36215, + 18033 => 23682, 18034 => 20062, 18035 => 20225, 18036 => 21551, 18037 => 22865, + 18038 => 30732, 18039 => 22120, 18040 => 27668, 18041 => 36804, 18042 => 24323, + 18043 => 27773, 18044 => 27875, 18045 => 35755, 18046 => 25488, 18209 => 24688, + 18210 => 27965, 18211 => 29301, 18212 => 25190, 18213 => 38030, 18214 => 38085, + 18215 => 21315, 18216 => 36801, 18217 => 31614, 18218 => 20191, 18219 => 35878, + 18220 => 20094, 18221 => 40660, 18222 => 38065, 18223 => 38067, 18224 => 21069, + 18225 => 28508, 18226 => 36963, 18227 => 27973, 18228 => 35892, 18229 => 22545, + 18230 => 23884, 18231 => 27424, 18232 => 27465, 18233 => 26538, 18234 => 21595, + 18235 => 33108, 18236 => 32652, 18237 => 22681, 18238 => 34103, 18239 => 24378, + 18240 => 25250, 18241 => 27207, 18242 => 38201, 18243 => 25970, 18244 => 24708, + 18245 => 26725, 18246 => 30631, 18247 => 20052, 18248 => 20392, 18249 => 24039, + 18250 => 38808, 18251 => 25772, 18252 => 32728, 18253 => 23789, 18254 => 20431, + 18255 => 31373, 18256 => 20999, 18257 => 33540, 18258 => 19988, 18259 => 24623, + 18260 => 31363, 18261 => 38054, 18262 => 20405, 18263 => 20146, 18264 => 31206, + 18265 => 29748, 18266 => 21220, 18267 => 33465, 18268 => 25810, 18269 => 31165, + 18270 => 23517, 18271 => 27777, 18272 => 38738, 18273 => 36731, 18274 => 27682, + 18275 => 20542, 18276 => 21375, 18277 => 28165, 18278 => 25806, 18279 => 26228, + 18280 => 27696, 18281 => 24773, 18282 => 39031, 18283 => 35831, 18284 => 24198, + 18285 => 29756, 18286 => 31351, 18287 => 31179, 18288 => 19992, 18289 => 37041, + 18290 => 29699, 18291 => 27714, 18292 => 22234, 18293 => 37195, 18294 => 27845, + 18295 => 36235, 18296 => 21306, 18297 => 34502, 18298 => 26354, 18299 => 36527, + 18300 => 23624, 18301 => 39537, 18302 => 28192, 18465 => 21462, 18466 => 23094, + 18467 => 40843, 18468 => 36259, 18469 => 21435, 18470 => 22280, 18471 => 39079, + 18472 => 26435, 18473 => 37275, 18474 => 27849, 18475 => 20840, 18476 => 30154, + 18477 => 25331, 18478 => 29356, 18479 => 21048, 18480 => 21149, 18481 => 32570, + 18482 => 28820, 18483 => 30264, 18484 => 21364, 18485 => 40522, 18486 => 27063, + 18487 => 30830, 18488 => 38592, 18489 => 35033, 18490 => 32676, 18491 => 28982, + 18492 => 29123, 18493 => 20873, 18494 => 26579, 18495 => 29924, 18496 => 22756, + 18497 => 25880, 18498 => 22199, 18499 => 35753, 18500 => 39286, 18501 => 25200, + 18502 => 32469, 18503 => 24825, 18504 => 28909, 18505 => 22764, 18506 => 20161, + 18507 => 20154, 18508 => 24525, 18509 => 38887, 18510 => 20219, 18511 => 35748, + 18512 => 20995, 18513 => 22922, 18514 => 32427, 18515 => 25172, 18516 => 20173, + 18517 => 26085, 18518 => 25102, 18519 => 33592, 18520 => 33993, 18521 => 33635, + 18522 => 34701, 18523 => 29076, 18524 => 28342, 18525 => 23481, 18526 => 32466, + 18527 => 20887, 18528 => 25545, 18529 => 26580, 18530 => 32905, 18531 => 33593, + 18532 => 34837, 18533 => 20754, 18534 => 23418, 18535 => 22914, 18536 => 36785, + 18537 => 20083, 18538 => 27741, 18539 => 20837, 18540 => 35109, 18541 => 36719, + 18542 => 38446, 18543 => 34122, 18544 => 29790, 18545 => 38160, 18546 => 38384, + 18547 => 28070, 18548 => 33509, 18549 => 24369, 18550 => 25746, 18551 => 27922, + 18552 => 33832, 18553 => 33134, 18554 => 40131, 18555 => 22622, 18556 => 36187, + 18557 => 19977, 18558 => 21441, 18721 => 20254, 18722 => 25955, 18723 => 26705, + 18724 => 21971, 18725 => 20007, 18726 => 25620, 18727 => 39578, 18728 => 25195, + 18729 => 23234, 18730 => 29791, 18731 => 33394, 18732 => 28073, 18733 => 26862, + 18734 => 20711, 18735 => 33678, 18736 => 30722, 18737 => 26432, 18738 => 21049, + 18739 => 27801, 18740 => 32433, 18741 => 20667, 18742 => 21861, 18743 => 29022, + 18744 => 31579, 18745 => 26194, 18746 => 29642, 18747 => 33515, 18748 => 26441, + 18749 => 23665, 18750 => 21024, 18751 => 29053, 18752 => 34923, 18753 => 38378, + 18754 => 38485, 18755 => 25797, 18756 => 36193, 18757 => 33203, 18758 => 21892, + 18759 => 27733, 18760 => 25159, 18761 => 32558, 18762 => 22674, 18763 => 20260, + 18764 => 21830, 18765 => 36175, 18766 => 26188, 18767 => 19978, 18768 => 23578, + 18769 => 35059, 18770 => 26786, 18771 => 25422, 18772 => 31245, 18773 => 28903, + 18774 => 33421, 18775 => 21242, 18776 => 38902, 18777 => 23569, 18778 => 21736, + 18779 => 37045, 18780 => 32461, 18781 => 22882, 18782 => 36170, 18783 => 34503, + 18784 => 33292, 18785 => 33293, 18786 => 36198, 18787 => 25668, 18788 => 23556, + 18789 => 24913, 18790 => 28041, 18791 => 31038, 18792 => 35774, 18793 => 30775, + 18794 => 30003, 18795 => 21627, 18796 => 20280, 18797 => 36523, 18798 => 28145, + 18799 => 23072, 18800 => 32453, 18801 => 31070, 18802 => 27784, 18803 => 23457, + 18804 => 23158, 18805 => 29978, 18806 => 32958, 18807 => 24910, 18808 => 28183, + 18809 => 22768, 18810 => 29983, 18811 => 29989, 18812 => 29298, 18813 => 21319, + 18814 => 32499, 18977 => 30465, 18978 => 30427, 18979 => 21097, 18980 => 32988, + 18981 => 22307, 18982 => 24072, 18983 => 22833, 18984 => 29422, 18985 => 26045, + 18986 => 28287, 18987 => 35799, 18988 => 23608, 18989 => 34417, 18990 => 21313, + 18991 => 30707, 18992 => 25342, 18993 => 26102, 18994 => 20160, 18995 => 39135, + 18996 => 34432, 18997 => 23454, 18998 => 35782, 18999 => 21490, 19000 => 30690, + 19001 => 20351, 19002 => 23630, 19003 => 39542, 19004 => 22987, 19005 => 24335, + 19006 => 31034, 19007 => 22763, 19008 => 19990, 19009 => 26623, 19010 => 20107, + 19011 => 25325, 19012 => 35475, 19013 => 36893, 19014 => 21183, 19015 => 26159, + 19016 => 21980, 19017 => 22124, 19018 => 36866, 19019 => 20181, 19020 => 20365, + 19021 => 37322, 19022 => 39280, 19023 => 27663, 19024 => 24066, 19025 => 24643, + 19026 => 23460, 19027 => 35270, 19028 => 35797, 19029 => 25910, 19030 => 25163, + 19031 => 39318, 19032 => 23432, 19033 => 23551, 19034 => 25480, 19035 => 21806, + 19036 => 21463, 19037 => 30246, 19038 => 20861, 19039 => 34092, 19040 => 26530, + 19041 => 26803, 19042 => 27530, 19043 => 25234, 19044 => 36755, 19045 => 21460, + 19046 => 33298, 19047 => 28113, 19048 => 30095, 19049 => 20070, 19050 => 36174, + 19051 => 23408, 19052 => 29087, 19053 => 34223, 19054 => 26257, 19055 => 26329, + 19056 => 32626, 19057 => 34560, 19058 => 40653, 19059 => 40736, 19060 => 23646, + 19061 => 26415, 19062 => 36848, 19063 => 26641, 19064 => 26463, 19065 => 25101, + 19066 => 31446, 19067 => 22661, 19068 => 24246, 19069 => 25968, 19070 => 28465, + 19233 => 24661, 19234 => 21047, 19235 => 32781, 19236 => 25684, 19237 => 34928, + 19238 => 29993, 19239 => 24069, 19240 => 26643, 19241 => 25332, 19242 => 38684, + 19243 => 21452, 19244 => 29245, 19245 => 35841, 19246 => 27700, 19247 => 30561, + 19248 => 31246, 19249 => 21550, 19250 => 30636, 19251 => 39034, 19252 => 33308, + 19253 => 35828, 19254 => 30805, 19255 => 26388, 19256 => 28865, 19257 => 26031, + 19258 => 25749, 19259 => 22070, 19260 => 24605, 19261 => 31169, 19262 => 21496, + 19263 => 19997, 19264 => 27515, 19265 => 32902, 19266 => 23546, 19267 => 21987, + 19268 => 22235, 19269 => 20282, 19270 => 20284, 19271 => 39282, 19272 => 24051, + 19273 => 26494, 19274 => 32824, 19275 => 24578, 19276 => 39042, 19277 => 36865, + 19278 => 23435, 19279 => 35772, 19280 => 35829, 19281 => 25628, 19282 => 33368, + 19283 => 25822, 19284 => 22013, 19285 => 33487, 19286 => 37221, 19287 => 20439, + 19288 => 32032, 19289 => 36895, 19290 => 31903, 19291 => 20723, 19292 => 22609, + 19293 => 28335, 19294 => 23487, 19295 => 35785, 19296 => 32899, 19297 => 37240, + 19298 => 33948, 19299 => 31639, 19300 => 34429, 19301 => 38539, 19302 => 38543, + 19303 => 32485, 19304 => 39635, 19305 => 30862, 19306 => 23681, 19307 => 31319, + 19308 => 36930, 19309 => 38567, 19310 => 31071, 19311 => 23385, 19312 => 25439, + 19313 => 31499, 19314 => 34001, 19315 => 26797, 19316 => 21766, 19317 => 32553, + 19318 => 29712, 19319 => 32034, 19320 => 38145, 19321 => 25152, 19322 => 22604, + 19323 => 20182, 19324 => 23427, 19325 => 22905, 19326 => 22612, 19489 => 29549, + 19490 => 25374, 19491 => 36427, 19492 => 36367, 19493 => 32974, 19494 => 33492, + 19495 => 25260, 19496 => 21488, 19497 => 27888, 19498 => 37214, 19499 => 22826, + 19500 => 24577, 19501 => 27760, 19502 => 22349, 19503 => 25674, 19504 => 36138, + 19505 => 30251, 19506 => 28393, 19507 => 22363, 19508 => 27264, 19509 => 30192, + 19510 => 28525, 19511 => 35885, 19512 => 35848, 19513 => 22374, 19514 => 27631, + 19515 => 34962, 19516 => 30899, 19517 => 25506, 19518 => 21497, 19519 => 28845, + 19520 => 27748, 19521 => 22616, 19522 => 25642, 19523 => 22530, 19524 => 26848, + 19525 => 33179, 19526 => 21776, 19527 => 31958, 19528 => 20504, 19529 => 36538, + 19530 => 28108, 19531 => 36255, 19532 => 28907, 19533 => 25487, 19534 => 28059, + 19535 => 28372, 19536 => 32486, 19537 => 33796, 19538 => 26691, 19539 => 36867, + 19540 => 28120, 19541 => 38518, 19542 => 35752, 19543 => 22871, 19544 => 29305, + 19545 => 34276, 19546 => 33150, 19547 => 30140, 19548 => 35466, 19549 => 26799, + 19550 => 21076, 19551 => 36386, 19552 => 38161, 19553 => 25552, 19554 => 39064, + 19555 => 36420, 19556 => 21884, 19557 => 20307, 19558 => 26367, 19559 => 22159, + 19560 => 24789, 19561 => 28053, 19562 => 21059, 19563 => 23625, 19564 => 22825, + 19565 => 28155, 19566 => 22635, 19567 => 30000, 19568 => 29980, 19569 => 24684, + 19570 => 33300, 19571 => 33094, 19572 => 25361, 19573 => 26465, 19574 => 36834, + 19575 => 30522, 19576 => 36339, 19577 => 36148, 19578 => 38081, 19579 => 24086, + 19580 => 21381, 19581 => 21548, 19582 => 28867, 19745 => 27712, 19746 => 24311, + 19747 => 20572, 19748 => 20141, 19749 => 24237, 19750 => 25402, 19751 => 33351, + 19752 => 36890, 19753 => 26704, 19754 => 37230, 19755 => 30643, 19756 => 21516, + 19757 => 38108, 19758 => 24420, 19759 => 31461, 19760 => 26742, 19761 => 25413, + 19762 => 31570, 19763 => 32479, 19764 => 30171, 19765 => 20599, 19766 => 25237, + 19767 => 22836, 19768 => 36879, 19769 => 20984, 19770 => 31171, 19771 => 31361, + 19772 => 22270, 19773 => 24466, 19774 => 36884, 19775 => 28034, 19776 => 23648, + 19777 => 22303, 19778 => 21520, 19779 => 20820, 19780 => 28237, 19781 => 22242, + 19782 => 25512, 19783 => 39059, 19784 => 33151, 19785 => 34581, 19786 => 35114, + 19787 => 36864, 19788 => 21534, 19789 => 23663, 19790 => 33216, 19791 => 25302, + 19792 => 25176, 19793 => 33073, 19794 => 40501, 19795 => 38464, 19796 => 39534, + 19797 => 39548, 19798 => 26925, 19799 => 22949, 19800 => 25299, 19801 => 21822, + 19802 => 25366, 19803 => 21703, 19804 => 34521, 19805 => 27964, 19806 => 23043, + 19807 => 29926, 19808 => 34972, 19809 => 27498, 19810 => 22806, 19811 => 35916, + 19812 => 24367, 19813 => 28286, 19814 => 29609, 19815 => 39037, 19816 => 20024, + 19817 => 28919, 19818 => 23436, 19819 => 30871, 19820 => 25405, 19821 => 26202, + 19822 => 30358, 19823 => 24779, 19824 => 23451, 19825 => 23113, 19826 => 19975, + 19827 => 33109, 19828 => 27754, 19829 => 29579, 19830 => 20129, 19831 => 26505, + 19832 => 32593, 19833 => 24448, 19834 => 26106, 19835 => 26395, 19836 => 24536, + 19837 => 22916, 19838 => 23041, 20001 => 24013, 20002 => 24494, 20003 => 21361, + 20004 => 38886, 20005 => 36829, 20006 => 26693, 20007 => 22260, 20008 => 21807, + 20009 => 24799, 20010 => 20026, 20011 => 28493, 20012 => 32500, 20013 => 33479, + 20014 => 33806, 20015 => 22996, 20016 => 20255, 20017 => 20266, 20018 => 23614, + 20019 => 32428, 20020 => 26410, 20021 => 34074, 20022 => 21619, 20023 => 30031, + 20024 => 32963, 20025 => 21890, 20026 => 39759, 20027 => 20301, 20028 => 28205, + 20029 => 35859, 20030 => 23561, 20031 => 24944, 20032 => 21355, 20033 => 30239, + 20034 => 28201, 20035 => 34442, 20036 => 25991, 20037 => 38395, 20038 => 32441, + 20039 => 21563, 20040 => 31283, 20041 => 32010, 20042 => 38382, 20043 => 21985, + 20044 => 32705, 20045 => 29934, 20046 => 25373, 20047 => 34583, 20048 => 28065, + 20049 => 31389, 20050 => 25105, 20051 => 26017, 20052 => 21351, 20053 => 25569, + 20054 => 27779, 20055 => 24043, 20056 => 21596, 20057 => 38056, 20058 => 20044, + 20059 => 27745, 20060 => 35820, 20061 => 23627, 20062 => 26080, 20063 => 33436, + 20064 => 26791, 20065 => 21566, 20066 => 21556, 20067 => 27595, 20068 => 27494, + 20069 => 20116, 20070 => 25410, 20071 => 21320, 20072 => 33310, 20073 => 20237, + 20074 => 20398, 20075 => 22366, 20076 => 25098, 20077 => 38654, 20078 => 26212, + 20079 => 29289, 20080 => 21247, 20081 => 21153, 20082 => 24735, 20083 => 35823, + 20084 => 26132, 20085 => 29081, 20086 => 26512, 20087 => 35199, 20088 => 30802, + 20089 => 30717, 20090 => 26224, 20091 => 22075, 20092 => 21560, 20093 => 38177, + 20094 => 29306, 20257 => 31232, 20258 => 24687, 20259 => 24076, 20260 => 24713, + 20261 => 33181, 20262 => 22805, 20263 => 24796, 20264 => 29060, 20265 => 28911, + 20266 => 28330, 20267 => 27728, 20268 => 29312, 20269 => 27268, 20270 => 34989, + 20271 => 24109, 20272 => 20064, 20273 => 23219, 20274 => 21916, 20275 => 38115, + 20276 => 27927, 20277 => 31995, 20278 => 38553, 20279 => 25103, 20280 => 32454, + 20281 => 30606, 20282 => 34430, 20283 => 21283, 20284 => 38686, 20285 => 36758, + 20286 => 26247, 20287 => 23777, 20288 => 20384, 20289 => 29421, 20290 => 19979, + 20291 => 21414, 20292 => 22799, 20293 => 21523, 20294 => 25472, 20295 => 38184, + 20296 => 20808, 20297 => 20185, 20298 => 40092, 20299 => 32420, 20300 => 21688, + 20301 => 36132, 20302 => 34900, 20303 => 33335, 20304 => 38386, 20305 => 28046, + 20306 => 24358, 20307 => 23244, 20308 => 26174, 20309 => 38505, 20310 => 29616, + 20311 => 29486, 20312 => 21439, 20313 => 33146, 20314 => 39301, 20315 => 32673, + 20316 => 23466, 20317 => 38519, 20318 => 38480, 20319 => 32447, 20320 => 30456, + 20321 => 21410, 20322 => 38262, 20323 => 39321, 20324 => 31665, 20325 => 35140, + 20326 => 28248, 20327 => 20065, 20328 => 32724, 20329 => 31077, 20330 => 35814, + 20331 => 24819, 20332 => 21709, 20333 => 20139, 20334 => 39033, 20335 => 24055, + 20336 => 27233, 20337 => 20687, 20338 => 21521, 20339 => 35937, 20340 => 33831, + 20341 => 30813, 20342 => 38660, 20343 => 21066, 20344 => 21742, 20345 => 22179, + 20346 => 38144, 20347 => 28040, 20348 => 23477, 20349 => 28102, 20350 => 26195, + 20513 => 23567, 20514 => 23389, 20515 => 26657, 20516 => 32918, 20517 => 21880, + 20518 => 31505, 20519 => 25928, 20520 => 26964, 20521 => 20123, 20522 => 27463, + 20523 => 34638, 20524 => 38795, 20525 => 21327, 20526 => 25375, 20527 => 25658, + 20528 => 37034, 20529 => 26012, 20530 => 32961, 20531 => 35856, 20532 => 20889, + 20533 => 26800, 20534 => 21368, 20535 => 34809, 20536 => 25032, 20537 => 27844, + 20538 => 27899, 20539 => 35874, 20540 => 23633, 20541 => 34218, 20542 => 33455, + 20543 => 38156, 20544 => 27427, 20545 => 36763, 20546 => 26032, 20547 => 24571, + 20548 => 24515, 20549 => 20449, 20550 => 34885, 20551 => 26143, 20552 => 33125, + 20553 => 29481, 20554 => 24826, 20555 => 20852, 20556 => 21009, 20557 => 22411, + 20558 => 24418, 20559 => 37026, 20560 => 34892, 20561 => 37266, 20562 => 24184, + 20563 => 26447, 20564 => 24615, 20565 => 22995, 20566 => 20804, 20567 => 20982, + 20568 => 33016, 20569 => 21256, 20570 => 27769, 20571 => 38596, 20572 => 29066, + 20573 => 20241, 20574 => 20462, 20575 => 32670, 20576 => 26429, 20577 => 21957, + 20578 => 38152, 20579 => 31168, 20580 => 34966, 20581 => 32483, 20582 => 22687, + 20583 => 25100, 20584 => 38656, 20585 => 34394, 20586 => 22040, 20587 => 39035, + 20588 => 24464, 20589 => 35768, 20590 => 33988, 20591 => 37207, 20592 => 21465, + 20593 => 26093, 20594 => 24207, 20595 => 30044, 20596 => 24676, 20597 => 32110, + 20598 => 23167, 20599 => 32490, 20600 => 32493, 20601 => 36713, 20602 => 21927, + 20603 => 23459, 20604 => 24748, 20605 => 26059, 20606 => 29572, 20769 => 36873, + 20770 => 30307, 20771 => 30505, 20772 => 32474, 20773 => 38772, 20774 => 34203, + 20775 => 23398, 20776 => 31348, 20777 => 38634, 20778 => 34880, 20779 => 21195, + 20780 => 29071, 20781 => 24490, 20782 => 26092, 20783 => 35810, 20784 => 23547, + 20785 => 39535, 20786 => 24033, 20787 => 27529, 20788 => 27739, 20789 => 35757, + 20790 => 35759, 20791 => 36874, 20792 => 36805, 20793 => 21387, 20794 => 25276, + 20795 => 40486, 20796 => 40493, 20797 => 21568, 20798 => 20011, 20799 => 33469, + 20800 => 29273, 20801 => 34460, 20802 => 23830, 20803 => 34905, 20804 => 28079, + 20805 => 38597, 20806 => 21713, 20807 => 20122, 20808 => 35766, 20809 => 28937, + 20810 => 21693, 20811 => 38409, 20812 => 28895, 20813 => 28153, 20814 => 30416, + 20815 => 20005, 20816 => 30740, 20817 => 34578, 20818 => 23721, 20819 => 24310, + 20820 => 35328, 20821 => 39068, 20822 => 38414, 20823 => 28814, 20824 => 27839, + 20825 => 22852, 20826 => 25513, 20827 => 30524, 20828 => 34893, 20829 => 28436, + 20830 => 33395, 20831 => 22576, 20832 => 29141, 20833 => 21388, 20834 => 30746, + 20835 => 38593, 20836 => 21761, 20837 => 24422, 20838 => 28976, 20839 => 23476, + 20840 => 35866, 20841 => 39564, 20842 => 27523, 20843 => 22830, 20844 => 40495, + 20845 => 31207, 20846 => 26472, 20847 => 25196, 20848 => 20335, 20849 => 30113, + 20850 => 32650, 20851 => 27915, 20852 => 38451, 20853 => 27687, 20854 => 20208, + 20855 => 30162, 20856 => 20859, 20857 => 26679, 20858 => 28478, 20859 => 36992, + 20860 => 33136, 20861 => 22934, 20862 => 29814, 21025 => 25671, 21026 => 23591, + 21027 => 36965, 21028 => 31377, 21029 => 35875, 21030 => 23002, 21031 => 21676, + 21032 => 33280, 21033 => 33647, 21034 => 35201, 21035 => 32768, 21036 => 26928, + 21037 => 22094, 21038 => 32822, 21039 => 29239, 21040 => 37326, 21041 => 20918, + 21042 => 20063, 21043 => 39029, 21044 => 25494, 21045 => 19994, 21046 => 21494, + 21047 => 26355, 21048 => 33099, 21049 => 22812, 21050 => 28082, 21051 => 19968, + 21052 => 22777, 21053 => 21307, 21054 => 25558, 21055 => 38129, 21056 => 20381, + 21057 => 20234, 21058 => 34915, 21059 => 39056, 21060 => 22839, 21061 => 36951, + 21062 => 31227, 21063 => 20202, 21064 => 33008, 21065 => 30097, 21066 => 27778, + 21067 => 23452, 21068 => 23016, 21069 => 24413, 21070 => 26885, 21071 => 34433, + 21072 => 20506, 21073 => 24050, 21074 => 20057, 21075 => 30691, 21076 => 20197, + 21077 => 33402, 21078 => 25233, 21079 => 26131, 21080 => 37009, 21081 => 23673, + 21082 => 20159, 21083 => 24441, 21084 => 33222, 21085 => 36920, 21086 => 32900, + 21087 => 30123, 21088 => 20134, 21089 => 35028, 21090 => 24847, 21091 => 27589, + 21092 => 24518, 21093 => 20041, 21094 => 30410, 21095 => 28322, 21096 => 35811, + 21097 => 35758, 21098 => 35850, 21099 => 35793, 21100 => 24322, 21101 => 32764, + 21102 => 32716, 21103 => 32462, 21104 => 33589, 21105 => 33643, 21106 => 22240, + 21107 => 27575, 21108 => 38899, 21109 => 38452, 21110 => 23035, 21111 => 21535, + 21112 => 38134, 21113 => 28139, 21114 => 23493, 21115 => 39278, 21116 => 23609, + 21117 => 24341, 21118 => 38544, 21281 => 21360, 21282 => 33521, 21283 => 27185, + 21284 => 23156, 21285 => 40560, 21286 => 24212, 21287 => 32552, 21288 => 33721, + 21289 => 33828, 21290 => 33829, 21291 => 33639, 21292 => 34631, 21293 => 36814, + 21294 => 36194, 21295 => 30408, 21296 => 24433, 21297 => 39062, 21298 => 30828, + 21299 => 26144, 21300 => 21727, 21301 => 25317, 21302 => 20323, 21303 => 33219, + 21304 => 30152, 21305 => 24248, 21306 => 38605, 21307 => 36362, 21308 => 34553, + 21309 => 21647, 21310 => 27891, 21311 => 28044, 21312 => 27704, 21313 => 24703, + 21314 => 21191, 21315 => 29992, 21316 => 24189, 21317 => 20248, 21318 => 24736, + 21319 => 24551, 21320 => 23588, 21321 => 30001, 21322 => 37038, 21323 => 38080, + 21324 => 29369, 21325 => 27833, 21326 => 28216, 21327 => 37193, 21328 => 26377, + 21329 => 21451, 21330 => 21491, 21331 => 20305, 21332 => 37321, 21333 => 35825, + 21334 => 21448, 21335 => 24188, 21336 => 36802, 21337 => 28132, 21338 => 20110, + 21339 => 30402, 21340 => 27014, 21341 => 34398, 21342 => 24858, 21343 => 33286, + 21344 => 20313, 21345 => 20446, 21346 => 36926, 21347 => 40060, 21348 => 24841, + 21349 => 28189, 21350 => 28180, 21351 => 38533, 21352 => 20104, 21353 => 23089, + 21354 => 38632, 21355 => 19982, 21356 => 23679, 21357 => 31161, 21358 => 23431, + 21359 => 35821, 21360 => 32701, 21361 => 29577, 21362 => 22495, 21363 => 33419, + 21364 => 37057, 21365 => 21505, 21366 => 36935, 21367 => 21947, 21368 => 23786, + 21369 => 24481, 21370 => 24840, 21371 => 27442, 21372 => 29425, 21373 => 32946, + 21374 => 35465, 21537 => 28020, 21538 => 23507, 21539 => 35029, 21540 => 39044, + 21541 => 35947, 21542 => 39533, 21543 => 40499, 21544 => 28170, 21545 => 20900, + 21546 => 20803, 21547 => 22435, 21548 => 34945, 21549 => 21407, 21550 => 25588, + 21551 => 36757, 21552 => 22253, 21553 => 21592, 21554 => 22278, 21555 => 29503, + 21556 => 28304, 21557 => 32536, 21558 => 36828, 21559 => 33489, 21560 => 24895, + 21561 => 24616, 21562 => 38498, 21563 => 26352, 21564 => 32422, 21565 => 36234, + 21566 => 36291, 21567 => 38053, 21568 => 23731, 21569 => 31908, 21570 => 26376, + 21571 => 24742, 21572 => 38405, 21573 => 32792, 21574 => 20113, 21575 => 37095, + 21576 => 21248, 21577 => 38504, 21578 => 20801, 21579 => 36816, 21580 => 34164, + 21581 => 37213, 21582 => 26197, 21583 => 38901, 21584 => 23381, 21585 => 21277, + 21586 => 30776, 21587 => 26434, 21588 => 26685, 21589 => 21705, 21590 => 28798, + 21591 => 23472, 21592 => 36733, 21593 => 20877, 21594 => 22312, 21595 => 21681, + 21596 => 25874, 21597 => 26242, 21598 => 36190, 21599 => 36163, 21600 => 33039, + 21601 => 33900, 21602 => 36973, 21603 => 31967, 21604 => 20991, 21605 => 34299, + 21606 => 26531, 21607 => 26089, 21608 => 28577, 21609 => 34468, 21610 => 36481, + 21611 => 22122, 21612 => 36896, 21613 => 30338, 21614 => 28790, 21615 => 29157, + 21616 => 36131, 21617 => 25321, 21618 => 21017, 21619 => 27901, 21620 => 36156, + 21621 => 24590, 21622 => 22686, 21623 => 24974, 21624 => 26366, 21625 => 36192, + 21626 => 25166, 21627 => 21939, 21628 => 28195, 21629 => 26413, 21630 => 36711, + 21793 => 38113, 21794 => 38392, 21795 => 30504, 21796 => 26629, 21797 => 27048, + 21798 => 21643, 21799 => 20045, 21800 => 28856, 21801 => 35784, 21802 => 25688, + 21803 => 25995, 21804 => 23429, 21805 => 31364, 21806 => 20538, 21807 => 23528, + 21808 => 30651, 21809 => 27617, 21810 => 35449, 21811 => 31896, 21812 => 27838, + 21813 => 30415, 21814 => 26025, 21815 => 36759, 21816 => 23853, 21817 => 23637, + 21818 => 34360, 21819 => 26632, 21820 => 21344, 21821 => 25112, 21822 => 31449, + 21823 => 28251, 21824 => 32509, 21825 => 27167, 21826 => 31456, 21827 => 24432, + 21828 => 28467, 21829 => 24352, 21830 => 25484, 21831 => 28072, 21832 => 26454, + 21833 => 19976, 21834 => 24080, 21835 => 36134, 21836 => 20183, 21837 => 32960, + 21838 => 30260, 21839 => 38556, 21840 => 25307, 21841 => 26157, 21842 => 25214, + 21843 => 27836, 21844 => 36213, 21845 => 29031, 21846 => 32617, 21847 => 20806, + 21848 => 32903, 21849 => 21484, 21850 => 36974, 21851 => 25240, 21852 => 21746, + 21853 => 34544, 21854 => 36761, 21855 => 32773, 21856 => 38167, 21857 => 34071, + 21858 => 36825, 21859 => 27993, 21860 => 29645, 21861 => 26015, 21862 => 30495, + 21863 => 29956, 21864 => 30759, 21865 => 33275, 21866 => 36126, 21867 => 38024, + 21868 => 20390, 21869 => 26517, 21870 => 30137, 21871 => 35786, 21872 => 38663, + 21873 => 25391, 21874 => 38215, 21875 => 38453, 21876 => 33976, 21877 => 25379, + 21878 => 30529, 21879 => 24449, 21880 => 29424, 21881 => 20105, 21882 => 24596, + 21883 => 25972, 21884 => 25327, 21885 => 27491, 21886 => 25919, 22049 => 24103, + 22050 => 30151, 22051 => 37073, 22052 => 35777, 22053 => 33437, 22054 => 26525, + 22055 => 25903, 22056 => 21553, 22057 => 34584, 22058 => 30693, 22059 => 32930, + 22060 => 33026, 22061 => 27713, 22062 => 20043, 22063 => 32455, 22064 => 32844, + 22065 => 30452, 22066 => 26893, 22067 => 27542, 22068 => 25191, 22069 => 20540, + 22070 => 20356, 22071 => 22336, 22072 => 25351, 22073 => 27490, 22074 => 36286, + 22075 => 21482, 22076 => 26088, 22077 => 32440, 22078 => 24535, 22079 => 25370, + 22080 => 25527, 22081 => 33267, 22082 => 33268, 22083 => 32622, 22084 => 24092, + 22085 => 23769, 22086 => 21046, 22087 => 26234, 22088 => 31209, 22089 => 31258, + 22090 => 36136, 22091 => 28825, 22092 => 30164, 22093 => 28382, 22094 => 27835, + 22095 => 31378, 22096 => 20013, 22097 => 30405, 22098 => 24544, 22099 => 38047, + 22100 => 34935, 22101 => 32456, 22102 => 31181, 22103 => 32959, 22104 => 37325, + 22105 => 20210, 22106 => 20247, 22107 => 33311, 22108 => 21608, 22109 => 24030, + 22110 => 27954, 22111 => 35788, 22112 => 31909, 22113 => 36724, 22114 => 32920, + 22115 => 24090, 22116 => 21650, 22117 => 30385, 22118 => 23449, 22119 => 26172, + 22120 => 39588, 22121 => 29664, 22122 => 26666, 22123 => 34523, 22124 => 26417, + 22125 => 29482, 22126 => 35832, 22127 => 35803, 22128 => 36880, 22129 => 31481, + 22130 => 28891, 22131 => 29038, 22132 => 25284, 22133 => 30633, 22134 => 22065, + 22135 => 20027, 22136 => 33879, 22137 => 26609, 22138 => 21161, 22139 => 34496, + 22140 => 36142, 22141 => 38136, 22142 => 31569, 22305 => 20303, 22306 => 27880, + 22307 => 31069, 22308 => 39547, 22309 => 25235, 22310 => 29226, 22311 => 25341, + 22312 => 19987, 22313 => 30742, 22314 => 36716, 22315 => 25776, 22316 => 36186, + 22317 => 31686, 22318 => 26729, 22319 => 24196, 22320 => 35013, 22321 => 22918, + 22322 => 25758, 22323 => 22766, 22324 => 29366, 22325 => 26894, 22326 => 38181, + 22327 => 36861, 22328 => 36184, 22329 => 22368, 22330 => 32512, 22331 => 35846, + 22332 => 20934, 22333 => 25417, 22334 => 25305, 22335 => 21331, 22336 => 26700, + 22337 => 29730, 22338 => 33537, 22339 => 37196, 22340 => 21828, 22341 => 30528, + 22342 => 28796, 22343 => 27978, 22344 => 20857, 22345 => 21672, 22346 => 36164, + 22347 => 23039, 22348 => 28363, 22349 => 28100, 22350 => 23388, 22351 => 32043, + 22352 => 20180, 22353 => 31869, 22354 => 28371, 22355 => 23376, 22356 => 33258, + 22357 => 28173, 22358 => 23383, 22359 => 39683, 22360 => 26837, 22361 => 36394, + 22362 => 23447, 22363 => 32508, 22364 => 24635, 22365 => 32437, 22366 => 37049, + 22367 => 36208, 22368 => 22863, 22369 => 25549, 22370 => 31199, 22371 => 36275, + 22372 => 21330, 22373 => 26063, 22374 => 31062, 22375 => 35781, 22376 => 38459, + 22377 => 32452, 22378 => 38075, 22379 => 32386, 22380 => 22068, 22381 => 37257, + 22382 => 26368, 22383 => 32618, 22384 => 23562, 22385 => 36981, 22386 => 26152, + 22387 => 24038, 22388 => 20304, 22389 => 26590, 22390 => 20570, 22391 => 20316, + 22392 => 22352, 22393 => 24231, 22561 => 20109, 22562 => 19980, 22563 => 20800, + 22564 => 19984, 22565 => 24319, 22566 => 21317, 22567 => 19989, 22568 => 20120, + 22569 => 19998, 22570 => 39730, 22571 => 23404, 22572 => 22121, 22573 => 20008, + 22574 => 31162, 22575 => 20031, 22576 => 21269, 22577 => 20039, 22578 => 22829, + 22579 => 29243, 22580 => 21358, 22581 => 27664, 22582 => 22239, 22583 => 32996, + 22584 => 39319, 22585 => 27603, 22586 => 30590, 22587 => 40727, 22588 => 20022, + 22589 => 20127, 22590 => 40720, 22591 => 20060, 22592 => 20073, 22593 => 20115, + 22594 => 33416, 22595 => 23387, 22596 => 21868, 22597 => 22031, 22598 => 20164, + 22599 => 21389, 22600 => 21405, 22601 => 21411, 22602 => 21413, 22603 => 21422, + 22604 => 38757, 22605 => 36189, 22606 => 21274, 22607 => 21493, 22608 => 21286, + 22609 => 21294, 22610 => 21310, 22611 => 36188, 22612 => 21350, 22613 => 21347, + 22614 => 20994, 22615 => 21000, 22616 => 21006, 22617 => 21037, 22618 => 21043, + 22619 => 21055, 22620 => 21056, 22621 => 21068, 22622 => 21086, 22623 => 21089, + 22624 => 21084, 22625 => 33967, 22626 => 21117, 22627 => 21122, 22628 => 21121, + 22629 => 21136, 22630 => 21139, 22631 => 20866, 22632 => 32596, 22633 => 20155, + 22634 => 20163, 22635 => 20169, 22636 => 20162, 22637 => 20200, 22638 => 20193, + 22639 => 20203, 22640 => 20190, 22641 => 20251, 22642 => 20211, 22643 => 20258, + 22644 => 20324, 22645 => 20213, 22646 => 20261, 22647 => 20263, 22648 => 20233, + 22649 => 20267, 22650 => 20318, 22651 => 20327, 22652 => 25912, 22653 => 20314, + 22654 => 20317, 22817 => 20319, 22818 => 20311, 22819 => 20274, 22820 => 20285, + 22821 => 20342, 22822 => 20340, 22823 => 20369, 22824 => 20361, 22825 => 20355, + 22826 => 20367, 22827 => 20350, 22828 => 20347, 22829 => 20394, 22830 => 20348, + 22831 => 20396, 22832 => 20372, 22833 => 20454, 22834 => 20456, 22835 => 20458, + 22836 => 20421, 22837 => 20442, 22838 => 20451, 22839 => 20444, 22840 => 20433, + 22841 => 20447, 22842 => 20472, 22843 => 20521, 22844 => 20556, 22845 => 20467, + 22846 => 20524, 22847 => 20495, 22848 => 20526, 22849 => 20525, 22850 => 20478, + 22851 => 20508, 22852 => 20492, 22853 => 20517, 22854 => 20520, 22855 => 20606, + 22856 => 20547, 22857 => 20565, 22858 => 20552, 22859 => 20558, 22860 => 20588, + 22861 => 20603, 22862 => 20645, 22863 => 20647, 22864 => 20649, 22865 => 20666, + 22866 => 20694, 22867 => 20742, 22868 => 20717, 22869 => 20716, 22870 => 20710, + 22871 => 20718, 22872 => 20743, 22873 => 20747, 22874 => 20189, 22875 => 27709, + 22876 => 20312, 22877 => 20325, 22878 => 20430, 22879 => 40864, 22880 => 27718, + 22881 => 31860, 22882 => 20846, 22883 => 24061, 22884 => 40649, 22885 => 39320, + 22886 => 20865, 22887 => 22804, 22888 => 21241, 22889 => 21261, 22890 => 35335, + 22891 => 21264, 22892 => 20971, 22893 => 22809, 22894 => 20821, 22895 => 20128, + 22896 => 20822, 22897 => 20147, 22898 => 34926, 22899 => 34980, 22900 => 20149, + 22901 => 33044, 22902 => 35026, 22903 => 31104, 22904 => 23348, 22905 => 34819, + 22906 => 32696, 22907 => 20907, 22908 => 20913, 22909 => 20925, 22910 => 20924, + 23073 => 20935, 23074 => 20886, 23075 => 20898, 23076 => 20901, 23077 => 35744, + 23078 => 35750, 23079 => 35751, 23080 => 35754, 23081 => 35764, 23082 => 35765, + 23083 => 35767, 23084 => 35778, 23085 => 35779, 23086 => 35787, 23087 => 35791, + 23088 => 35790, 23089 => 35794, 23090 => 35795, 23091 => 35796, 23092 => 35798, + 23093 => 35800, 23094 => 35801, 23095 => 35804, 23096 => 35807, 23097 => 35808, + 23098 => 35812, 23099 => 35816, 23100 => 35817, 23101 => 35822, 23102 => 35824, + 23103 => 35827, 23104 => 35830, 23105 => 35833, 23106 => 35836, 23107 => 35839, + 23108 => 35840, 23109 => 35842, 23110 => 35844, 23111 => 35847, 23112 => 35852, + 23113 => 35855, 23114 => 35857, 23115 => 35858, 23116 => 35860, 23117 => 35861, + 23118 => 35862, 23119 => 35865, 23120 => 35867, 23121 => 35864, 23122 => 35869, + 23123 => 35871, 23124 => 35872, 23125 => 35873, 23126 => 35877, 23127 => 35879, + 23128 => 35882, 23129 => 35883, 23130 => 35886, 23131 => 35887, 23132 => 35890, + 23133 => 35891, 23134 => 35893, 23135 => 35894, 23136 => 21353, 23137 => 21370, + 23138 => 38429, 23139 => 38434, 23140 => 38433, 23141 => 38449, 23142 => 38442, + 23143 => 38461, 23144 => 38460, 23145 => 38466, 23146 => 38473, 23147 => 38484, + 23148 => 38495, 23149 => 38503, 23150 => 38508, 23151 => 38514, 23152 => 38516, + 23153 => 38536, 23154 => 38541, 23155 => 38551, 23156 => 38576, 23157 => 37015, + 23158 => 37019, 23159 => 37021, 23160 => 37017, 23161 => 37036, 23162 => 37025, + 23163 => 37044, 23164 => 37043, 23165 => 37046, 23166 => 37050, 23329 => 37048, + 23330 => 37040, 23331 => 37071, 23332 => 37061, 23333 => 37054, 23334 => 37072, + 23335 => 37060, 23336 => 37063, 23337 => 37075, 23338 => 37094, 23339 => 37090, + 23340 => 37084, 23341 => 37079, 23342 => 37083, 23343 => 37099, 23344 => 37103, + 23345 => 37118, 23346 => 37124, 23347 => 37154, 23348 => 37150, 23349 => 37155, + 23350 => 37169, 23351 => 37167, 23352 => 37177, 23353 => 37187, 23354 => 37190, + 23355 => 21005, 23356 => 22850, 23357 => 21154, 23358 => 21164, 23359 => 21165, + 23360 => 21182, 23361 => 21759, 23362 => 21200, 23363 => 21206, 23364 => 21232, + 23365 => 21471, 23366 => 29166, 23367 => 30669, 23368 => 24308, 23369 => 20981, + 23370 => 20988, 23371 => 39727, 23372 => 21430, 23373 => 24321, 23374 => 30042, + 23375 => 24047, 23376 => 22348, 23377 => 22441, 23378 => 22433, 23379 => 22654, + 23380 => 22716, 23381 => 22725, 23382 => 22737, 23383 => 22313, 23384 => 22316, + 23385 => 22314, 23386 => 22323, 23387 => 22329, 23388 => 22318, 23389 => 22319, + 23390 => 22364, 23391 => 22331, 23392 => 22338, 23393 => 22377, 23394 => 22405, + 23395 => 22379, 23396 => 22406, 23397 => 22396, 23398 => 22395, 23399 => 22376, + 23400 => 22381, 23401 => 22390, 23402 => 22387, 23403 => 22445, 23404 => 22436, + 23405 => 22412, 23406 => 22450, 23407 => 22479, 23408 => 22439, 23409 => 22452, + 23410 => 22419, 23411 => 22432, 23412 => 22485, 23413 => 22488, 23414 => 22490, + 23415 => 22489, 23416 => 22482, 23417 => 22456, 23418 => 22516, 23419 => 22511, + 23420 => 22520, 23421 => 22500, 23422 => 22493, 23585 => 22539, 23586 => 22541, + 23587 => 22525, 23588 => 22509, 23589 => 22528, 23590 => 22558, 23591 => 22553, + 23592 => 22596, 23593 => 22560, 23594 => 22629, 23595 => 22636, 23596 => 22657, + 23597 => 22665, 23598 => 22682, 23599 => 22656, 23600 => 39336, 23601 => 40729, + 23602 => 25087, 23603 => 33401, 23604 => 33405, 23605 => 33407, 23606 => 33423, + 23607 => 33418, 23608 => 33448, 23609 => 33412, 23610 => 33422, 23611 => 33425, + 23612 => 33431, 23613 => 33433, 23614 => 33451, 23615 => 33464, 23616 => 33470, + 23617 => 33456, 23618 => 33480, 23619 => 33482, 23620 => 33507, 23621 => 33432, + 23622 => 33463, 23623 => 33454, 23624 => 33483, 23625 => 33484, 23626 => 33473, + 23627 => 33449, 23628 => 33460, 23629 => 33441, 23630 => 33450, 23631 => 33439, + 23632 => 33476, 23633 => 33486, 23634 => 33444, 23635 => 33505, 23636 => 33545, + 23637 => 33527, 23638 => 33508, 23639 => 33551, 23640 => 33543, 23641 => 33500, + 23642 => 33524, 23643 => 33490, 23644 => 33496, 23645 => 33548, 23646 => 33531, + 23647 => 33491, 23648 => 33553, 23649 => 33562, 23650 => 33542, 23651 => 33556, + 23652 => 33557, 23653 => 33504, 23654 => 33493, 23655 => 33564, 23656 => 33617, + 23657 => 33627, 23658 => 33628, 23659 => 33544, 23660 => 33682, 23661 => 33596, + 23662 => 33588, 23663 => 33585, 23664 => 33691, 23665 => 33630, 23666 => 33583, + 23667 => 33615, 23668 => 33607, 23669 => 33603, 23670 => 33631, 23671 => 33600, + 23672 => 33559, 23673 => 33632, 23674 => 33581, 23675 => 33594, 23676 => 33587, + 23677 => 33638, 23678 => 33637, 23841 => 33640, 23842 => 33563, 23843 => 33641, + 23844 => 33644, 23845 => 33642, 23846 => 33645, 23847 => 33646, 23848 => 33712, + 23849 => 33656, 23850 => 33715, 23851 => 33716, 23852 => 33696, 23853 => 33706, + 23854 => 33683, 23855 => 33692, 23856 => 33669, 23857 => 33660, 23858 => 33718, + 23859 => 33705, 23860 => 33661, 23861 => 33720, 23862 => 33659, 23863 => 33688, + 23864 => 33694, 23865 => 33704, 23866 => 33722, 23867 => 33724, 23868 => 33729, + 23869 => 33793, 23870 => 33765, 23871 => 33752, 23872 => 22535, 23873 => 33816, + 23874 => 33803, 23875 => 33757, 23876 => 33789, 23877 => 33750, 23878 => 33820, + 23879 => 33848, 23880 => 33809, 23881 => 33798, 23882 => 33748, 23883 => 33759, + 23884 => 33807, 23885 => 33795, 23886 => 33784, 23887 => 33785, 23888 => 33770, + 23889 => 33733, 23890 => 33728, 23891 => 33830, 23892 => 33776, 23893 => 33761, + 23894 => 33884, 23895 => 33873, 23896 => 33882, 23897 => 33881, 23898 => 33907, + 23899 => 33927, 23900 => 33928, 23901 => 33914, 23902 => 33929, 23903 => 33912, + 23904 => 33852, 23905 => 33862, 23906 => 33897, 23907 => 33910, 23908 => 33932, + 23909 => 33934, 23910 => 33841, 23911 => 33901, 23912 => 33985, 23913 => 33997, + 23914 => 34000, 23915 => 34022, 23916 => 33981, 23917 => 34003, 23918 => 33994, + 23919 => 33983, 23920 => 33978, 23921 => 34016, 23922 => 33953, 23923 => 33977, + 23924 => 33972, 23925 => 33943, 23926 => 34021, 23927 => 34019, 23928 => 34060, + 23929 => 29965, 23930 => 34104, 23931 => 34032, 23932 => 34105, 23933 => 34079, + 23934 => 34106, 24097 => 34134, 24098 => 34107, 24099 => 34047, 24100 => 34044, + 24101 => 34137, 24102 => 34120, 24103 => 34152, 24104 => 34148, 24105 => 34142, + 24106 => 34170, 24107 => 30626, 24108 => 34115, 24109 => 34162, 24110 => 34171, + 24111 => 34212, 24112 => 34216, 24113 => 34183, 24114 => 34191, 24115 => 34169, + 24116 => 34222, 24117 => 34204, 24118 => 34181, 24119 => 34233, 24120 => 34231, + 24121 => 34224, 24122 => 34259, 24123 => 34241, 24124 => 34268, 24125 => 34303, + 24126 => 34343, 24127 => 34309, 24128 => 34345, 24129 => 34326, 24130 => 34364, + 24131 => 24318, 24132 => 24328, 24133 => 22844, 24134 => 22849, 24135 => 32823, + 24136 => 22869, 24137 => 22874, 24138 => 22872, 24139 => 21263, 24140 => 23586, + 24141 => 23589, 24142 => 23596, 24143 => 23604, 24144 => 25164, 24145 => 25194, + 24146 => 25247, 24147 => 25275, 24148 => 25290, 24149 => 25306, 24150 => 25303, + 24151 => 25326, 24152 => 25378, 24153 => 25334, 24154 => 25401, 24155 => 25419, + 24156 => 25411, 24157 => 25517, 24158 => 25590, 24159 => 25457, 24160 => 25466, + 24161 => 25486, 24162 => 25524, 24163 => 25453, 24164 => 25516, 24165 => 25482, + 24166 => 25449, 24167 => 25518, 24168 => 25532, 24169 => 25586, 24170 => 25592, + 24171 => 25568, 24172 => 25599, 24173 => 25540, 24174 => 25566, 24175 => 25550, + 24176 => 25682, 24177 => 25542, 24178 => 25534, 24179 => 25669, 24180 => 25665, + 24181 => 25611, 24182 => 25627, 24183 => 25632, 24184 => 25612, 24185 => 25638, + 24186 => 25633, 24187 => 25694, 24188 => 25732, 24189 => 25709, 24190 => 25750, + 24353 => 25722, 24354 => 25783, 24355 => 25784, 24356 => 25753, 24357 => 25786, + 24358 => 25792, 24359 => 25808, 24360 => 25815, 24361 => 25828, 24362 => 25826, + 24363 => 25865, 24364 => 25893, 24365 => 25902, 24366 => 24331, 24367 => 24530, + 24368 => 29977, 24369 => 24337, 24370 => 21343, 24371 => 21489, 24372 => 21501, + 24373 => 21481, 24374 => 21480, 24375 => 21499, 24376 => 21522, 24377 => 21526, + 24378 => 21510, 24379 => 21579, 24380 => 21586, 24381 => 21587, 24382 => 21588, + 24383 => 21590, 24384 => 21571, 24385 => 21537, 24386 => 21591, 24387 => 21593, + 24388 => 21539, 24389 => 21554, 24390 => 21634, 24391 => 21652, 24392 => 21623, + 24393 => 21617, 24394 => 21604, 24395 => 21658, 24396 => 21659, 24397 => 21636, + 24398 => 21622, 24399 => 21606, 24400 => 21661, 24401 => 21712, 24402 => 21677, + 24403 => 21698, 24404 => 21684, 24405 => 21714, 24406 => 21671, 24407 => 21670, + 24408 => 21715, 24409 => 21716, 24410 => 21618, 24411 => 21667, 24412 => 21717, + 24413 => 21691, 24414 => 21695, 24415 => 21708, 24416 => 21721, 24417 => 21722, + 24418 => 21724, 24419 => 21673, 24420 => 21674, 24421 => 21668, 24422 => 21725, + 24423 => 21711, 24424 => 21726, 24425 => 21787, 24426 => 21735, 24427 => 21792, + 24428 => 21757, 24429 => 21780, 24430 => 21747, 24431 => 21794, 24432 => 21795, + 24433 => 21775, 24434 => 21777, 24435 => 21799, 24436 => 21802, 24437 => 21863, + 24438 => 21903, 24439 => 21941, 24440 => 21833, 24441 => 21869, 24442 => 21825, + 24443 => 21845, 24444 => 21823, 24445 => 21840, 24446 => 21820, 24609 => 21815, + 24610 => 21846, 24611 => 21877, 24612 => 21878, 24613 => 21879, 24614 => 21811, + 24615 => 21808, 24616 => 21852, 24617 => 21899, 24618 => 21970, 24619 => 21891, + 24620 => 21937, 24621 => 21945, 24622 => 21896, 24623 => 21889, 24624 => 21919, + 24625 => 21886, 24626 => 21974, 24627 => 21905, 24628 => 21883, 24629 => 21983, + 24630 => 21949, 24631 => 21950, 24632 => 21908, 24633 => 21913, 24634 => 21994, + 24635 => 22007, 24636 => 21961, 24637 => 22047, 24638 => 21969, 24639 => 21995, + 24640 => 21996, 24641 => 21972, 24642 => 21990, 24643 => 21981, 24644 => 21956, + 24645 => 21999, 24646 => 21989, 24647 => 22002, 24648 => 22003, 24649 => 21964, + 24650 => 21965, 24651 => 21992, 24652 => 22005, 24653 => 21988, 24654 => 36756, + 24655 => 22046, 24656 => 22024, 24657 => 22028, 24658 => 22017, 24659 => 22052, + 24660 => 22051, 24661 => 22014, 24662 => 22016, 24663 => 22055, 24664 => 22061, + 24665 => 22104, 24666 => 22073, 24667 => 22103, 24668 => 22060, 24669 => 22093, + 24670 => 22114, 24671 => 22105, 24672 => 22108, 24673 => 22092, 24674 => 22100, + 24675 => 22150, 24676 => 22116, 24677 => 22129, 24678 => 22123, 24679 => 22139, + 24680 => 22140, 24681 => 22149, 24682 => 22163, 24683 => 22191, 24684 => 22228, + 24685 => 22231, 24686 => 22237, 24687 => 22241, 24688 => 22261, 24689 => 22251, + 24690 => 22265, 24691 => 22271, 24692 => 22276, 24693 => 22282, 24694 => 22281, + 24695 => 22300, 24696 => 24079, 24697 => 24089, 24698 => 24084, 24699 => 24081, + 24700 => 24113, 24701 => 24123, 24702 => 24124, 24865 => 24119, 24866 => 24132, + 24867 => 24148, 24868 => 24155, 24869 => 24158, 24870 => 24161, 24871 => 23692, + 24872 => 23674, 24873 => 23693, 24874 => 23696, 24875 => 23702, 24876 => 23688, + 24877 => 23704, 24878 => 23705, 24879 => 23697, 24880 => 23706, 24881 => 23708, + 24882 => 23733, 24883 => 23714, 24884 => 23741, 24885 => 23724, 24886 => 23723, + 24887 => 23729, 24888 => 23715, 24889 => 23745, 24890 => 23735, 24891 => 23748, + 24892 => 23762, 24893 => 23780, 24894 => 23755, 24895 => 23781, 24896 => 23810, + 24897 => 23811, 24898 => 23847, 24899 => 23846, 24900 => 23854, 24901 => 23844, + 24902 => 23838, 24903 => 23814, 24904 => 23835, 24905 => 23896, 24906 => 23870, + 24907 => 23860, 24908 => 23869, 24909 => 23916, 24910 => 23899, 24911 => 23919, + 24912 => 23901, 24913 => 23915, 24914 => 23883, 24915 => 23882, 24916 => 23913, + 24917 => 23924, 24918 => 23938, 24919 => 23961, 24920 => 23965, 24921 => 35955, + 24922 => 23991, 24923 => 24005, 24924 => 24435, 24925 => 24439, 24926 => 24450, + 24927 => 24455, 24928 => 24457, 24929 => 24460, 24930 => 24469, 24931 => 24473, + 24932 => 24476, 24933 => 24488, 24934 => 24493, 24935 => 24501, 24936 => 24508, + 24937 => 34914, 24938 => 24417, 24939 => 29357, 24940 => 29360, 24941 => 29364, + 24942 => 29367, 24943 => 29368, 24944 => 29379, 24945 => 29377, 24946 => 29390, + 24947 => 29389, 24948 => 29394, 24949 => 29416, 24950 => 29423, 24951 => 29417, + 24952 => 29426, 24953 => 29428, 24954 => 29431, 24955 => 29441, 24956 => 29427, + 24957 => 29443, 24958 => 29434, 25121 => 29435, 25122 => 29463, 25123 => 29459, + 25124 => 29473, 25125 => 29450, 25126 => 29470, 25127 => 29469, 25128 => 29461, + 25129 => 29474, 25130 => 29497, 25131 => 29477, 25132 => 29484, 25133 => 29496, + 25134 => 29489, 25135 => 29520, 25136 => 29517, 25137 => 29527, 25138 => 29536, + 25139 => 29548, 25140 => 29551, 25141 => 29566, 25142 => 33307, 25143 => 22821, + 25144 => 39143, 25145 => 22820, 25146 => 22786, 25147 => 39267, 25148 => 39271, + 25149 => 39272, 25150 => 39273, 25151 => 39274, 25152 => 39275, 25153 => 39276, + 25154 => 39284, 25155 => 39287, 25156 => 39293, 25157 => 39296, 25158 => 39300, + 25159 => 39303, 25160 => 39306, 25161 => 39309, 25162 => 39312, 25163 => 39313, + 25164 => 39315, 25165 => 39316, 25166 => 39317, 25167 => 24192, 25168 => 24209, + 25169 => 24203, 25170 => 24214, 25171 => 24229, 25172 => 24224, 25173 => 24249, + 25174 => 24245, 25175 => 24254, 25176 => 24243, 25177 => 36179, 25178 => 24274, + 25179 => 24273, 25180 => 24283, 25181 => 24296, 25182 => 24298, 25183 => 33210, + 25184 => 24516, 25185 => 24521, 25186 => 24534, 25187 => 24527, 25188 => 24579, + 25189 => 24558, 25190 => 24580, 25191 => 24545, 25192 => 24548, 25193 => 24574, + 25194 => 24581, 25195 => 24582, 25196 => 24554, 25197 => 24557, 25198 => 24568, + 25199 => 24601, 25200 => 24629, 25201 => 24614, 25202 => 24603, 25203 => 24591, + 25204 => 24589, 25205 => 24617, 25206 => 24619, 25207 => 24586, 25208 => 24639, + 25209 => 24609, 25210 => 24696, 25211 => 24697, 25212 => 24699, 25213 => 24698, + 25214 => 24642, 25377 => 24682, 25378 => 24701, 25379 => 24726, 25380 => 24730, + 25381 => 24749, 25382 => 24733, 25383 => 24707, 25384 => 24722, 25385 => 24716, + 25386 => 24731, 25387 => 24812, 25388 => 24763, 25389 => 24753, 25390 => 24797, + 25391 => 24792, 25392 => 24774, 25393 => 24794, 25394 => 24756, 25395 => 24864, + 25396 => 24870, 25397 => 24853, 25398 => 24867, 25399 => 24820, 25400 => 24832, + 25401 => 24846, 25402 => 24875, 25403 => 24906, 25404 => 24949, 25405 => 25004, + 25406 => 24980, 25407 => 24999, 25408 => 25015, 25409 => 25044, 25410 => 25077, + 25411 => 24541, 25412 => 38579, 25413 => 38377, 25414 => 38379, 25415 => 38385, + 25416 => 38387, 25417 => 38389, 25418 => 38390, 25419 => 38396, 25420 => 38398, + 25421 => 38403, 25422 => 38404, 25423 => 38406, 25424 => 38408, 25425 => 38410, + 25426 => 38411, 25427 => 38412, 25428 => 38413, 25429 => 38415, 25430 => 38418, + 25431 => 38421, 25432 => 38422, 25433 => 38423, 25434 => 38425, 25435 => 38426, + 25436 => 20012, 25437 => 29247, 25438 => 25109, 25439 => 27701, 25440 => 27732, + 25441 => 27740, 25442 => 27722, 25443 => 27811, 25444 => 27781, 25445 => 27792, + 25446 => 27796, 25447 => 27788, 25448 => 27752, 25449 => 27753, 25450 => 27764, + 25451 => 27766, 25452 => 27782, 25453 => 27817, 25454 => 27856, 25455 => 27860, + 25456 => 27821, 25457 => 27895, 25458 => 27896, 25459 => 27889, 25460 => 27863, + 25461 => 27826, 25462 => 27872, 25463 => 27862, 25464 => 27898, 25465 => 27883, + 25466 => 27886, 25467 => 27825, 25468 => 27859, 25469 => 27887, 25470 => 27902, + 25633 => 27961, 25634 => 27943, 25635 => 27916, 25636 => 27971, 25637 => 27976, + 25638 => 27911, 25639 => 27908, 25640 => 27929, 25641 => 27918, 25642 => 27947, + 25643 => 27981, 25644 => 27950, 25645 => 27957, 25646 => 27930, 25647 => 27983, + 25648 => 27986, 25649 => 27988, 25650 => 27955, 25651 => 28049, 25652 => 28015, + 25653 => 28062, 25654 => 28064, 25655 => 27998, 25656 => 28051, 25657 => 28052, + 25658 => 27996, 25659 => 28000, 25660 => 28028, 25661 => 28003, 25662 => 28186, + 25663 => 28103, 25664 => 28101, 25665 => 28126, 25666 => 28174, 25667 => 28095, + 25668 => 28128, 25669 => 28177, 25670 => 28134, 25671 => 28125, 25672 => 28121, + 25673 => 28182, 25674 => 28075, 25675 => 28172, 25676 => 28078, 25677 => 28203, + 25678 => 28270, 25679 => 28238, 25680 => 28267, 25681 => 28338, 25682 => 28255, + 25683 => 28294, 25684 => 28243, 25685 => 28244, 25686 => 28210, 25687 => 28197, + 25688 => 28228, 25689 => 28383, 25690 => 28337, 25691 => 28312, 25692 => 28384, + 25693 => 28461, 25694 => 28386, 25695 => 28325, 25696 => 28327, 25697 => 28349, + 25698 => 28347, 25699 => 28343, 25700 => 28375, 25701 => 28340, 25702 => 28367, + 25703 => 28303, 25704 => 28354, 25705 => 28319, 25706 => 28514, 25707 => 28486, + 25708 => 28487, 25709 => 28452, 25710 => 28437, 25711 => 28409, 25712 => 28463, + 25713 => 28470, 25714 => 28491, 25715 => 28532, 25716 => 28458, 25717 => 28425, + 25718 => 28457, 25719 => 28553, 25720 => 28557, 25721 => 28556, 25722 => 28536, + 25723 => 28530, 25724 => 28540, 25725 => 28538, 25726 => 28625, 25889 => 28617, + 25890 => 28583, 25891 => 28601, 25892 => 28598, 25893 => 28610, 25894 => 28641, + 25895 => 28654, 25896 => 28638, 25897 => 28640, 25898 => 28655, 25899 => 28698, + 25900 => 28707, 25901 => 28699, 25902 => 28729, 25903 => 28725, 25904 => 28751, + 25905 => 28766, 25906 => 23424, 25907 => 23428, 25908 => 23445, 25909 => 23443, + 25910 => 23461, 25911 => 23480, 25912 => 29999, 25913 => 39582, 25914 => 25652, + 25915 => 23524, 25916 => 23534, 25917 => 35120, 25918 => 23536, 25919 => 36423, + 25920 => 35591, 25921 => 36790, 25922 => 36819, 25923 => 36821, 25924 => 36837, + 25925 => 36846, 25926 => 36836, 25927 => 36841, 25928 => 36838, 25929 => 36851, + 25930 => 36840, 25931 => 36869, 25932 => 36868, 25933 => 36875, 25934 => 36902, + 25935 => 36881, 25936 => 36877, 25937 => 36886, 25938 => 36897, 25939 => 36917, + 25940 => 36918, 25941 => 36909, 25942 => 36911, 25943 => 36932, 25944 => 36945, + 25945 => 36946, 25946 => 36944, 25947 => 36968, 25948 => 36952, 25949 => 36962, + 25950 => 36955, 25951 => 26297, 25952 => 36980, 25953 => 36989, 25954 => 36994, + 25955 => 37000, 25956 => 36995, 25957 => 37003, 25958 => 24400, 25959 => 24407, + 25960 => 24406, 25961 => 24408, 25962 => 23611, 25963 => 21675, 25964 => 23632, + 25965 => 23641, 25966 => 23409, 25967 => 23651, 25968 => 23654, 25969 => 32700, + 25970 => 24362, 25971 => 24361, 25972 => 24365, 25973 => 33396, 25974 => 24380, + 25975 => 39739, 25976 => 23662, 25977 => 22913, 25978 => 22915, 25979 => 22925, + 25980 => 22953, 25981 => 22954, 25982 => 22947, 26145 => 22935, 26146 => 22986, + 26147 => 22955, 26148 => 22942, 26149 => 22948, 26150 => 22994, 26151 => 22962, + 26152 => 22959, 26153 => 22999, 26154 => 22974, 26155 => 23045, 26156 => 23046, + 26157 => 23005, 26158 => 23048, 26159 => 23011, 26160 => 23000, 26161 => 23033, + 26162 => 23052, 26163 => 23049, 26164 => 23090, 26165 => 23092, 26166 => 23057, + 26167 => 23075, 26168 => 23059, 26169 => 23104, 26170 => 23143, 26171 => 23114, + 26172 => 23125, 26173 => 23100, 26174 => 23138, 26175 => 23157, 26176 => 33004, + 26177 => 23210, 26178 => 23195, 26179 => 23159, 26180 => 23162, 26181 => 23230, + 26182 => 23275, 26183 => 23218, 26184 => 23250, 26185 => 23252, 26186 => 23224, + 26187 => 23264, 26188 => 23267, 26189 => 23281, 26190 => 23254, 26191 => 23270, + 26192 => 23256, 26193 => 23260, 26194 => 23305, 26195 => 23319, 26196 => 23318, + 26197 => 23346, 26198 => 23351, 26199 => 23360, 26200 => 23573, 26201 => 23580, + 26202 => 23386, 26203 => 23397, 26204 => 23411, 26205 => 23377, 26206 => 23379, + 26207 => 23394, 26208 => 39541, 26209 => 39543, 26210 => 39544, 26211 => 39546, + 26212 => 39551, 26213 => 39549, 26214 => 39552, 26215 => 39553, 26216 => 39557, + 26217 => 39560, 26218 => 39562, 26219 => 39568, 26220 => 39570, 26221 => 39571, + 26222 => 39574, 26223 => 39576, 26224 => 39579, 26225 => 39580, 26226 => 39581, + 26227 => 39583, 26228 => 39584, 26229 => 39586, 26230 => 39587, 26231 => 39589, + 26232 => 39591, 26233 => 32415, 26234 => 32417, 26235 => 32419, 26236 => 32421, + 26237 => 32424, 26238 => 32425, 26401 => 32429, 26402 => 32432, 26403 => 32446, + 26404 => 32448, 26405 => 32449, 26406 => 32450, 26407 => 32457, 26408 => 32459, + 26409 => 32460, 26410 => 32464, 26411 => 32468, 26412 => 32471, 26413 => 32475, + 26414 => 32480, 26415 => 32481, 26416 => 32488, 26417 => 32491, 26418 => 32494, + 26419 => 32495, 26420 => 32497, 26421 => 32498, 26422 => 32525, 26423 => 32502, + 26424 => 32506, 26425 => 32507, 26426 => 32510, 26427 => 32513, 26428 => 32514, + 26429 => 32515, 26430 => 32519, 26431 => 32520, 26432 => 32523, 26433 => 32524, + 26434 => 32527, 26435 => 32529, 26436 => 32530, 26437 => 32535, 26438 => 32537, + 26439 => 32540, 26440 => 32539, 26441 => 32543, 26442 => 32545, 26443 => 32546, + 26444 => 32547, 26445 => 32548, 26446 => 32549, 26447 => 32550, 26448 => 32551, + 26449 => 32554, 26450 => 32555, 26451 => 32556, 26452 => 32557, 26453 => 32559, + 26454 => 32560, 26455 => 32561, 26456 => 32562, 26457 => 32563, 26458 => 32565, + 26459 => 24186, 26460 => 30079, 26461 => 24027, 26462 => 30014, 26463 => 37013, + 26464 => 29582, 26465 => 29585, 26466 => 29614, 26467 => 29602, 26468 => 29599, + 26469 => 29647, 26470 => 29634, 26471 => 29649, 26472 => 29623, 26473 => 29619, + 26474 => 29632, 26475 => 29641, 26476 => 29640, 26477 => 29669, 26478 => 29657, + 26479 => 39036, 26480 => 29706, 26481 => 29673, 26482 => 29671, 26483 => 29662, + 26484 => 29626, 26485 => 29682, 26486 => 29711, 26487 => 29738, 26488 => 29787, + 26489 => 29734, 26490 => 29733, 26491 => 29736, 26492 => 29744, 26493 => 29742, + 26494 => 29740, 26657 => 29723, 26658 => 29722, 26659 => 29761, 26660 => 29788, + 26661 => 29783, 26662 => 29781, 26663 => 29785, 26664 => 29815, 26665 => 29805, + 26666 => 29822, 26667 => 29852, 26668 => 29838, 26669 => 29824, 26670 => 29825, + 26671 => 29831, 26672 => 29835, 26673 => 29854, 26674 => 29864, 26675 => 29865, + 26676 => 29840, 26677 => 29863, 26678 => 29906, 26679 => 29882, 26680 => 38890, + 26681 => 38891, 26682 => 38892, 26683 => 26444, 26684 => 26451, 26685 => 26462, + 26686 => 26440, 26687 => 26473, 26688 => 26533, 26689 => 26503, 26690 => 26474, + 26691 => 26483, 26692 => 26520, 26693 => 26535, 26694 => 26485, 26695 => 26536, + 26696 => 26526, 26697 => 26541, 26698 => 26507, 26699 => 26487, 26700 => 26492, + 26701 => 26608, 26702 => 26633, 26703 => 26584, 26704 => 26634, 26705 => 26601, + 26706 => 26544, 26707 => 26636, 26708 => 26585, 26709 => 26549, 26710 => 26586, + 26711 => 26547, 26712 => 26589, 26713 => 26624, 26714 => 26563, 26715 => 26552, + 26716 => 26594, 26717 => 26638, 26718 => 26561, 26719 => 26621, 26720 => 26674, + 26721 => 26675, 26722 => 26720, 26723 => 26721, 26724 => 26702, 26725 => 26722, + 26726 => 26692, 26727 => 26724, 26728 => 26755, 26729 => 26653, 26730 => 26709, + 26731 => 26726, 26732 => 26689, 26733 => 26727, 26734 => 26688, 26735 => 26686, + 26736 => 26698, 26737 => 26697, 26738 => 26665, 26739 => 26805, 26740 => 26767, + 26741 => 26740, 26742 => 26743, 26743 => 26771, 26744 => 26731, 26745 => 26818, + 26746 => 26990, 26747 => 26876, 26748 => 26911, 26749 => 26912, 26750 => 26873, + 26913 => 26916, 26914 => 26864, 26915 => 26891, 26916 => 26881, 26917 => 26967, + 26918 => 26851, 26919 => 26896, 26920 => 26993, 26921 => 26937, 26922 => 26976, + 26923 => 26946, 26924 => 26973, 26925 => 27012, 26926 => 26987, 26927 => 27008, + 26928 => 27032, 26929 => 27000, 26930 => 26932, 26931 => 27084, 26932 => 27015, + 26933 => 27016, 26934 => 27086, 26935 => 27017, 26936 => 26982, 26937 => 26979, + 26938 => 27001, 26939 => 27035, 26940 => 27047, 26941 => 27067, 26942 => 27051, + 26943 => 27053, 26944 => 27092, 26945 => 27057, 26946 => 27073, 26947 => 27082, + 26948 => 27103, 26949 => 27029, 26950 => 27104, 26951 => 27021, 26952 => 27135, + 26953 => 27183, 26954 => 27117, 26955 => 27159, 26956 => 27160, 26957 => 27237, + 26958 => 27122, 26959 => 27204, 26960 => 27198, 26961 => 27296, 26962 => 27216, + 26963 => 27227, 26964 => 27189, 26965 => 27278, 26966 => 27257, 26967 => 27197, + 26968 => 27176, 26969 => 27224, 26970 => 27260, 26971 => 27281, 26972 => 27280, + 26973 => 27305, 26974 => 27287, 26975 => 27307, 26976 => 29495, 26977 => 29522, + 26978 => 27521, 26979 => 27522, 26980 => 27527, 26981 => 27524, 26982 => 27538, + 26983 => 27539, 26984 => 27533, 26985 => 27546, 26986 => 27547, 26987 => 27553, + 26988 => 27562, 26989 => 36715, 26990 => 36717, 26991 => 36721, 26992 => 36722, + 26993 => 36723, 26994 => 36725, 26995 => 36726, 26996 => 36728, 26997 => 36727, + 26998 => 36729, 26999 => 36730, 27000 => 36732, 27001 => 36734, 27002 => 36737, + 27003 => 36738, 27004 => 36740, 27005 => 36743, 27006 => 36747, 27169 => 36749, + 27170 => 36750, 27171 => 36751, 27172 => 36760, 27173 => 36762, 27174 => 36558, + 27175 => 25099, 27176 => 25111, 27177 => 25115, 27178 => 25119, 27179 => 25122, + 27180 => 25121, 27181 => 25125, 27182 => 25124, 27183 => 25132, 27184 => 33255, + 27185 => 29935, 27186 => 29940, 27187 => 29951, 27188 => 29967, 27189 => 29969, + 27190 => 29971, 27191 => 25908, 27192 => 26094, 27193 => 26095, 27194 => 26096, + 27195 => 26122, 27196 => 26137, 27197 => 26482, 27198 => 26115, 27199 => 26133, + 27200 => 26112, 27201 => 28805, 27202 => 26359, 27203 => 26141, 27204 => 26164, + 27205 => 26161, 27206 => 26166, 27207 => 26165, 27208 => 32774, 27209 => 26207, + 27210 => 26196, 27211 => 26177, 27212 => 26191, 27213 => 26198, 27214 => 26209, + 27215 => 26199, 27216 => 26231, 27217 => 26244, 27218 => 26252, 27219 => 26279, + 27220 => 26269, 27221 => 26302, 27222 => 26331, 27223 => 26332, 27224 => 26342, + 27225 => 26345, 27226 => 36146, 27227 => 36147, 27228 => 36150, 27229 => 36155, + 27230 => 36157, 27231 => 36160, 27232 => 36165, 27233 => 36166, 27234 => 36168, + 27235 => 36169, 27236 => 36167, 27237 => 36173, 27238 => 36181, 27239 => 36185, + 27240 => 35271, 27241 => 35274, 27242 => 35275, 27243 => 35276, 27244 => 35278, + 27245 => 35279, 27246 => 35280, 27247 => 35281, 27248 => 29294, 27249 => 29343, + 27250 => 29277, 27251 => 29286, 27252 => 29295, 27253 => 29310, 27254 => 29311, + 27255 => 29316, 27256 => 29323, 27257 => 29325, 27258 => 29327, 27259 => 29330, + 27260 => 25352, 27261 => 25394, 27262 => 25520, 27425 => 25663, 27426 => 25816, + 27427 => 32772, 27428 => 27626, 27429 => 27635, 27430 => 27645, 27431 => 27637, + 27432 => 27641, 27433 => 27653, 27434 => 27655, 27435 => 27654, 27436 => 27661, + 27437 => 27669, 27438 => 27672, 27439 => 27673, 27440 => 27674, 27441 => 27681, + 27442 => 27689, 27443 => 27684, 27444 => 27690, 27445 => 27698, 27446 => 25909, + 27447 => 25941, 27448 => 25963, 27449 => 29261, 27450 => 29266, 27451 => 29270, + 27452 => 29232, 27453 => 34402, 27454 => 21014, 27455 => 32927, 27456 => 32924, + 27457 => 32915, 27458 => 32956, 27459 => 26378, 27460 => 32957, 27461 => 32945, + 27462 => 32939, 27463 => 32941, 27464 => 32948, 27465 => 32951, 27466 => 32999, + 27467 => 33000, 27468 => 33001, 27469 => 33002, 27470 => 32987, 27471 => 32962, + 27472 => 32964, 27473 => 32985, 27474 => 32973, 27475 => 32983, 27476 => 26384, + 27477 => 32989, 27478 => 33003, 27479 => 33009, 27480 => 33012, 27481 => 33005, + 27482 => 33037, 27483 => 33038, 27484 => 33010, 27485 => 33020, 27486 => 26389, + 27487 => 33042, 27488 => 35930, 27489 => 33078, 27490 => 33054, 27491 => 33068, + 27492 => 33048, 27493 => 33074, 27494 => 33096, 27495 => 33100, 27496 => 33107, + 27497 => 33140, 27498 => 33113, 27499 => 33114, 27500 => 33137, 27501 => 33120, + 27502 => 33129, 27503 => 33148, 27504 => 33149, 27505 => 33133, 27506 => 33127, + 27507 => 22605, 27508 => 23221, 27509 => 33160, 27510 => 33154, 27511 => 33169, + 27512 => 28373, 27513 => 33187, 27514 => 33194, 27515 => 33228, 27516 => 26406, + 27517 => 33226, 27518 => 33211, 27681 => 33217, 27682 => 33190, 27683 => 27428, + 27684 => 27447, 27685 => 27449, 27686 => 27459, 27687 => 27462, 27688 => 27481, + 27689 => 39121, 27690 => 39122, 27691 => 39123, 27692 => 39125, 27693 => 39129, + 27694 => 39130, 27695 => 27571, 27696 => 24384, 27697 => 27586, 27698 => 35315, + 27699 => 26000, 27700 => 40785, 27701 => 26003, 27702 => 26044, 27703 => 26054, + 27704 => 26052, 27705 => 26051, 27706 => 26060, 27707 => 26062, 27708 => 26066, + 27709 => 26070, 27710 => 28800, 27711 => 28828, 27712 => 28822, 27713 => 28829, + 27714 => 28859, 27715 => 28864, 27716 => 28855, 27717 => 28843, 27718 => 28849, + 27719 => 28904, 27720 => 28874, 27721 => 28944, 27722 => 28947, 27723 => 28950, + 27724 => 28975, 27725 => 28977, 27726 => 29043, 27727 => 29020, 27728 => 29032, + 27729 => 28997, 27730 => 29042, 27731 => 29002, 27732 => 29048, 27733 => 29050, + 27734 => 29080, 27735 => 29107, 27736 => 29109, 27737 => 29096, 27738 => 29088, + 27739 => 29152, 27740 => 29140, 27741 => 29159, 27742 => 29177, 27743 => 29213, + 27744 => 29224, 27745 => 28780, 27746 => 28952, 27747 => 29030, 27748 => 29113, + 27749 => 25150, 27750 => 25149, 27751 => 25155, 27752 => 25160, 27753 => 25161, + 27754 => 31035, 27755 => 31040, 27756 => 31046, 27757 => 31049, 27758 => 31067, + 27759 => 31068, 27760 => 31059, 27761 => 31066, 27762 => 31074, 27763 => 31063, + 27764 => 31072, 27765 => 31087, 27766 => 31079, 27767 => 31098, 27768 => 31109, + 27769 => 31114, 27770 => 31130, 27771 => 31143, 27772 => 31155, 27773 => 24529, + 27774 => 24528, 27937 => 24636, 27938 => 24669, 27939 => 24666, 27940 => 24679, + 27941 => 24641, 27942 => 24665, 27943 => 24675, 27944 => 24747, 27945 => 24838, + 27946 => 24845, 27947 => 24925, 27948 => 25001, 27949 => 24989, 27950 => 25035, + 27951 => 25041, 27952 => 25094, 27953 => 32896, 27954 => 32895, 27955 => 27795, + 27956 => 27894, 27957 => 28156, 27958 => 30710, 27959 => 30712, 27960 => 30720, + 27961 => 30729, 27962 => 30743, 27963 => 30744, 27964 => 30737, 27965 => 26027, + 27966 => 30765, 27967 => 30748, 27968 => 30749, 27969 => 30777, 27970 => 30778, + 27971 => 30779, 27972 => 30751, 27973 => 30780, 27974 => 30757, 27975 => 30764, + 27976 => 30755, 27977 => 30761, 27978 => 30798, 27979 => 30829, 27980 => 30806, + 27981 => 30807, 27982 => 30758, 27983 => 30800, 27984 => 30791, 27985 => 30796, + 27986 => 30826, 27987 => 30875, 27988 => 30867, 27989 => 30874, 27990 => 30855, + 27991 => 30876, 27992 => 30881, 27993 => 30883, 27994 => 30898, 27995 => 30905, + 27996 => 30885, 27997 => 30932, 27998 => 30937, 27999 => 30921, 28000 => 30956, + 28001 => 30962, 28002 => 30981, 28003 => 30964, 28004 => 30995, 28005 => 31012, + 28006 => 31006, 28007 => 31028, 28008 => 40859, 28009 => 40697, 28010 => 40699, + 28011 => 40700, 28012 => 30449, 28013 => 30468, 28014 => 30477, 28015 => 30457, + 28016 => 30471, 28017 => 30472, 28018 => 30490, 28019 => 30498, 28020 => 30489, + 28021 => 30509, 28022 => 30502, 28023 => 30517, 28024 => 30520, 28025 => 30544, + 28026 => 30545, 28027 => 30535, 28028 => 30531, 28029 => 30554, 28030 => 30568, + 28193 => 30562, 28194 => 30565, 28195 => 30591, 28196 => 30605, 28197 => 30589, + 28198 => 30592, 28199 => 30604, 28200 => 30609, 28201 => 30623, 28202 => 30624, + 28203 => 30640, 28204 => 30645, 28205 => 30653, 28206 => 30010, 28207 => 30016, + 28208 => 30030, 28209 => 30027, 28210 => 30024, 28211 => 30043, 28212 => 30066, + 28213 => 30073, 28214 => 30083, 28215 => 32600, 28216 => 32609, 28217 => 32607, + 28218 => 35400, 28219 => 32616, 28220 => 32628, 28221 => 32625, 28222 => 32633, + 28223 => 32641, 28224 => 32638, 28225 => 30413, 28226 => 30437, 28227 => 34866, + 28228 => 38021, 28229 => 38022, 28230 => 38023, 28231 => 38027, 28232 => 38026, + 28233 => 38028, 28234 => 38029, 28235 => 38031, 28236 => 38032, 28237 => 38036, + 28238 => 38039, 28239 => 38037, 28240 => 38042, 28241 => 38043, 28242 => 38044, + 28243 => 38051, 28244 => 38052, 28245 => 38059, 28246 => 38058, 28247 => 38061, + 28248 => 38060, 28249 => 38063, 28250 => 38064, 28251 => 38066, 28252 => 38068, + 28253 => 38070, 28254 => 38071, 28255 => 38072, 28256 => 38073, 28257 => 38074, + 28258 => 38076, 28259 => 38077, 28260 => 38079, 28261 => 38084, 28262 => 38088, + 28263 => 38089, 28264 => 38090, 28265 => 38091, 28266 => 38092, 28267 => 38093, + 28268 => 38094, 28269 => 38096, 28270 => 38097, 28271 => 38098, 28272 => 38101, + 28273 => 38102, 28274 => 38103, 28275 => 38105, 28276 => 38104, 28277 => 38107, + 28278 => 38110, 28279 => 38111, 28280 => 38112, 28281 => 38114, 28282 => 38116, + 28283 => 38117, 28284 => 38119, 28285 => 38120, 28286 => 38122, 28449 => 38121, + 28450 => 38123, 28451 => 38126, 28452 => 38127, 28453 => 38131, 28454 => 38132, + 28455 => 38133, 28456 => 38135, 28457 => 38137, 28458 => 38140, 28459 => 38141, + 28460 => 38143, 28461 => 38147, 28462 => 38146, 28463 => 38150, 28464 => 38151, + 28465 => 38153, 28466 => 38154, 28467 => 38157, 28468 => 38158, 28469 => 38159, + 28470 => 38162, 28471 => 38163, 28472 => 38164, 28473 => 38165, 28474 => 38166, + 28475 => 38168, 28476 => 38171, 28477 => 38173, 28478 => 38174, 28479 => 38175, + 28480 => 38178, 28481 => 38186, 28482 => 38187, 28483 => 38185, 28484 => 38188, + 28485 => 38193, 28486 => 38194, 28487 => 38196, 28488 => 38198, 28489 => 38199, + 28490 => 38200, 28491 => 38204, 28492 => 38206, 28493 => 38207, 28494 => 38210, + 28495 => 38197, 28496 => 38212, 28497 => 38213, 28498 => 38214, 28499 => 38217, + 28500 => 38220, 28501 => 38222, 28502 => 38223, 28503 => 38226, 28504 => 38227, + 28505 => 38228, 28506 => 38230, 28507 => 38231, 28508 => 38232, 28509 => 38233, + 28510 => 38235, 28511 => 38238, 28512 => 38239, 28513 => 38237, 28514 => 38241, + 28515 => 38242, 28516 => 38244, 28517 => 38245, 28518 => 38246, 28519 => 38247, + 28520 => 38248, 28521 => 38249, 28522 => 38250, 28523 => 38251, 28524 => 38252, + 28525 => 38255, 28526 => 38257, 28527 => 38258, 28528 => 38259, 28529 => 38202, + 28530 => 30695, 28531 => 30700, 28532 => 38601, 28533 => 31189, 28534 => 31213, + 28535 => 31203, 28536 => 31211, 28537 => 31238, 28538 => 23879, 28539 => 31235, + 28540 => 31234, 28541 => 31262, 28542 => 31252, 28705 => 31289, 28706 => 31287, + 28707 => 31313, 28708 => 40655, 28709 => 39333, 28710 => 31344, 28711 => 30344, + 28712 => 30350, 28713 => 30355, 28714 => 30361, 28715 => 30372, 28716 => 29918, + 28717 => 29920, 28718 => 29996, 28719 => 40480, 28720 => 40482, 28721 => 40488, + 28722 => 40489, 28723 => 40490, 28724 => 40491, 28725 => 40492, 28726 => 40498, + 28727 => 40497, 28728 => 40502, 28729 => 40504, 28730 => 40503, 28731 => 40505, + 28732 => 40506, 28733 => 40510, 28734 => 40513, 28735 => 40514, 28736 => 40516, + 28737 => 40518, 28738 => 40519, 28739 => 40520, 28740 => 40521, 28741 => 40523, + 28742 => 40524, 28743 => 40526, 28744 => 40529, 28745 => 40533, 28746 => 40535, + 28747 => 40538, 28748 => 40539, 28749 => 40540, 28750 => 40542, 28751 => 40547, + 28752 => 40550, 28753 => 40551, 28754 => 40552, 28755 => 40553, 28756 => 40554, + 28757 => 40555, 28758 => 40556, 28759 => 40561, 28760 => 40557, 28761 => 40563, + 28762 => 30098, 28763 => 30100, 28764 => 30102, 28765 => 30112, 28766 => 30109, + 28767 => 30124, 28768 => 30115, 28769 => 30131, 28770 => 30132, 28771 => 30136, + 28772 => 30148, 28773 => 30129, 28774 => 30128, 28775 => 30147, 28776 => 30146, + 28777 => 30166, 28778 => 30157, 28779 => 30179, 28780 => 30184, 28781 => 30182, + 28782 => 30180, 28783 => 30187, 28784 => 30183, 28785 => 30211, 28786 => 30193, + 28787 => 30204, 28788 => 30207, 28789 => 30224, 28790 => 30208, 28791 => 30213, + 28792 => 30220, 28793 => 30231, 28794 => 30218, 28795 => 30245, 28796 => 30232, + 28797 => 30229, 28798 => 30233, 28961 => 30235, 28962 => 30268, 28963 => 30242, + 28964 => 30240, 28965 => 30272, 28966 => 30253, 28967 => 30256, 28968 => 30271, + 28969 => 30261, 28970 => 30275, 28971 => 30270, 28972 => 30259, 28973 => 30285, + 28974 => 30302, 28975 => 30292, 28976 => 30300, 28977 => 30294, 28978 => 30315, + 28979 => 30319, 28980 => 32714, 28981 => 31462, 28982 => 31352, 28983 => 31353, + 28984 => 31360, 28985 => 31366, 28986 => 31368, 28987 => 31381, 28988 => 31398, + 28989 => 31392, 28990 => 31404, 28991 => 31400, 28992 => 31405, 28993 => 31411, + 28994 => 34916, 28995 => 34921, 28996 => 34930, 28997 => 34941, 28998 => 34943, + 28999 => 34946, 29000 => 34978, 29001 => 35014, 29002 => 34999, 29003 => 35004, + 29004 => 35017, 29005 => 35042, 29006 => 35022, 29007 => 35043, 29008 => 35045, + 29009 => 35057, 29010 => 35098, 29011 => 35068, 29012 => 35048, 29013 => 35070, + 29014 => 35056, 29015 => 35105, 29016 => 35097, 29017 => 35091, 29018 => 35099, + 29019 => 35082, 29020 => 35124, 29021 => 35115, 29022 => 35126, 29023 => 35137, + 29024 => 35174, 29025 => 35195, 29026 => 30091, 29027 => 32997, 29028 => 30386, + 29029 => 30388, 29030 => 30684, 29031 => 32786, 29032 => 32788, 29033 => 32790, + 29034 => 32796, 29035 => 32800, 29036 => 32802, 29037 => 32805, 29038 => 32806, + 29039 => 32807, 29040 => 32809, 29041 => 32808, 29042 => 32817, 29043 => 32779, + 29044 => 32821, 29045 => 32835, 29046 => 32838, 29047 => 32845, 29048 => 32850, + 29049 => 32873, 29050 => 32881, 29051 => 35203, 29052 => 39032, 29053 => 39040, + 29054 => 39043, 29217 => 39049, 29218 => 39052, 29219 => 39053, 29220 => 39055, + 29221 => 39060, 29222 => 39066, 29223 => 39067, 29224 => 39070, 29225 => 39071, + 29226 => 39073, 29227 => 39074, 29228 => 39077, 29229 => 39078, 29230 => 34381, + 29231 => 34388, 29232 => 34412, 29233 => 34414, 29234 => 34431, 29235 => 34426, + 29236 => 34428, 29237 => 34427, 29238 => 34472, 29239 => 34445, 29240 => 34443, + 29241 => 34476, 29242 => 34461, 29243 => 34471, 29244 => 34467, 29245 => 34474, + 29246 => 34451, 29247 => 34473, 29248 => 34486, 29249 => 34500, 29250 => 34485, + 29251 => 34510, 29252 => 34480, 29253 => 34490, 29254 => 34481, 29255 => 34479, + 29256 => 34505, 29257 => 34511, 29258 => 34484, 29259 => 34537, 29260 => 34545, + 29261 => 34546, 29262 => 34541, 29263 => 34547, 29264 => 34512, 29265 => 34579, + 29266 => 34526, 29267 => 34548, 29268 => 34527, 29269 => 34520, 29270 => 34513, + 29271 => 34563, 29272 => 34567, 29273 => 34552, 29274 => 34568, 29275 => 34570, + 29276 => 34573, 29277 => 34569, 29278 => 34595, 29279 => 34619, 29280 => 34590, + 29281 => 34597, 29282 => 34606, 29283 => 34586, 29284 => 34622, 29285 => 34632, + 29286 => 34612, 29287 => 34609, 29288 => 34601, 29289 => 34615, 29290 => 34623, + 29291 => 34690, 29292 => 34594, 29293 => 34685, 29294 => 34686, 29295 => 34683, + 29296 => 34656, 29297 => 34672, 29298 => 34636, 29299 => 34670, 29300 => 34699, + 29301 => 34643, 29302 => 34659, 29303 => 34684, 29304 => 34660, 29305 => 34649, + 29306 => 34661, 29307 => 34707, 29308 => 34735, 29309 => 34728, 29310 => 34770, + 29473 => 34758, 29474 => 34696, 29475 => 34693, 29476 => 34733, 29477 => 34711, + 29478 => 34691, 29479 => 34731, 29480 => 34789, 29481 => 34732, 29482 => 34741, + 29483 => 34739, 29484 => 34763, 29485 => 34771, 29486 => 34749, 29487 => 34769, + 29488 => 34752, 29489 => 34762, 29490 => 34779, 29491 => 34794, 29492 => 34784, + 29493 => 34798, 29494 => 34838, 29495 => 34835, 29496 => 34814, 29497 => 34826, + 29498 => 34843, 29499 => 34849, 29500 => 34873, 29501 => 34876, 29502 => 32566, + 29503 => 32578, 29504 => 32580, 29505 => 32581, 29506 => 33296, 29507 => 31482, + 29508 => 31485, 29509 => 31496, 29510 => 31491, 29511 => 31492, 29512 => 31509, + 29513 => 31498, 29514 => 31531, 29515 => 31503, 29516 => 31559, 29517 => 31544, + 29518 => 31530, 29519 => 31513, 29520 => 31534, 29521 => 31537, 29522 => 31520, + 29523 => 31525, 29524 => 31524, 29525 => 31539, 29526 => 31550, 29527 => 31518, + 29528 => 31576, 29529 => 31578, 29530 => 31557, 29531 => 31605, 29532 => 31564, + 29533 => 31581, 29534 => 31584, 29535 => 31598, 29536 => 31611, 29537 => 31586, + 29538 => 31602, 29539 => 31601, 29540 => 31632, 29541 => 31654, 29542 => 31655, + 29543 => 31672, 29544 => 31660, 29545 => 31645, 29546 => 31656, 29547 => 31621, + 29548 => 31658, 29549 => 31644, 29550 => 31650, 29551 => 31659, 29552 => 31668, + 29553 => 31697, 29554 => 31681, 29555 => 31692, 29556 => 31709, 29557 => 31706, + 29558 => 31717, 29559 => 31718, 29560 => 31722, 29561 => 31756, 29562 => 31742, + 29563 => 31740, 29564 => 31759, 29565 => 31766, 29566 => 31755, 29729 => 31775, + 29730 => 31786, 29731 => 31782, 29732 => 31800, 29733 => 31809, 29734 => 31808, + 29735 => 33278, 29736 => 33281, 29737 => 33282, 29738 => 33284, 29739 => 33260, + 29740 => 34884, 29741 => 33313, 29742 => 33314, 29743 => 33315, 29744 => 33325, + 29745 => 33327, 29746 => 33320, 29747 => 33323, 29748 => 33336, 29749 => 33339, + 29750 => 33331, 29751 => 33332, 29752 => 33342, 29753 => 33348, 29754 => 33353, + 29755 => 33355, 29756 => 33359, 29757 => 33370, 29758 => 33375, 29759 => 33384, + 29760 => 34942, 29761 => 34949, 29762 => 34952, 29763 => 35032, 29764 => 35039, + 29765 => 35166, 29766 => 32669, 29767 => 32671, 29768 => 32679, 29769 => 32687, + 29770 => 32688, 29771 => 32690, 29772 => 31868, 29773 => 25929, 29774 => 31889, + 29775 => 31901, 29776 => 31900, 29777 => 31902, 29778 => 31906, 29779 => 31922, + 29780 => 31932, 29781 => 31933, 29782 => 31937, 29783 => 31943, 29784 => 31948, + 29785 => 31949, 29786 => 31944, 29787 => 31941, 29788 => 31959, 29789 => 31976, + 29790 => 33390, 29791 => 26280, 29792 => 32703, 29793 => 32718, 29794 => 32725, + 29795 => 32741, 29796 => 32737, 29797 => 32742, 29798 => 32745, 29799 => 32750, + 29800 => 32755, 29801 => 31992, 29802 => 32119, 29803 => 32166, 29804 => 32174, + 29805 => 32327, 29806 => 32411, 29807 => 40632, 29808 => 40628, 29809 => 36211, + 29810 => 36228, 29811 => 36244, 29812 => 36241, 29813 => 36273, 29814 => 36199, + 29815 => 36205, 29816 => 35911, 29817 => 35913, 29818 => 37194, 29819 => 37200, + 29820 => 37198, 29821 => 37199, 29822 => 37220, 29985 => 37218, 29986 => 37217, + 29987 => 37232, 29988 => 37225, 29989 => 37231, 29990 => 37245, 29991 => 37246, + 29992 => 37234, 29993 => 37236, 29994 => 37241, 29995 => 37260, 29996 => 37253, + 29997 => 37264, 29998 => 37261, 29999 => 37265, 30000 => 37282, 30001 => 37283, + 30002 => 37290, 30003 => 37293, 30004 => 37294, 30005 => 37295, 30006 => 37301, + 30007 => 37300, 30008 => 37306, 30009 => 35925, 30010 => 40574, 30011 => 36280, + 30012 => 36331, 30013 => 36357, 30014 => 36441, 30015 => 36457, 30016 => 36277, + 30017 => 36287, 30018 => 36284, 30019 => 36282, 30020 => 36292, 30021 => 36310, + 30022 => 36311, 30023 => 36314, 30024 => 36318, 30025 => 36302, 30026 => 36303, + 30027 => 36315, 30028 => 36294, 30029 => 36332, 30030 => 36343, 30031 => 36344, + 30032 => 36323, 30033 => 36345, 30034 => 36347, 30035 => 36324, 30036 => 36361, + 30037 => 36349, 30038 => 36372, 30039 => 36381, 30040 => 36383, 30041 => 36396, + 30042 => 36398, 30043 => 36387, 30044 => 36399, 30045 => 36410, 30046 => 36416, + 30047 => 36409, 30048 => 36405, 30049 => 36413, 30050 => 36401, 30051 => 36425, + 30052 => 36417, 30053 => 36418, 30054 => 36433, 30055 => 36434, 30056 => 36426, + 30057 => 36464, 30058 => 36470, 30059 => 36476, 30060 => 36463, 30061 => 36468, + 30062 => 36485, 30063 => 36495, 30064 => 36500, 30065 => 36496, 30066 => 36508, + 30067 => 36510, 30068 => 35960, 30069 => 35970, 30070 => 35978, 30071 => 35973, + 30072 => 35992, 30073 => 35988, 30074 => 26011, 30075 => 35286, 30076 => 35294, + 30077 => 35290, 30078 => 35292, 30241 => 35301, 30242 => 35307, 30243 => 35311, + 30244 => 35390, 30245 => 35622, 30246 => 38739, 30247 => 38633, 30248 => 38643, + 30249 => 38639, 30250 => 38662, 30251 => 38657, 30252 => 38664, 30253 => 38671, + 30254 => 38670, 30255 => 38698, 30256 => 38701, 30257 => 38704, 30258 => 38718, + 30259 => 40832, 30260 => 40835, 30261 => 40837, 30262 => 40838, 30263 => 40839, + 30264 => 40840, 30265 => 40841, 30266 => 40842, 30267 => 40844, 30268 => 40702, + 30269 => 40715, 30270 => 40717, 30271 => 38585, 30272 => 38588, 30273 => 38589, + 30274 => 38606, 30275 => 38610, 30276 => 30655, 30277 => 38624, 30278 => 37518, + 30279 => 37550, 30280 => 37576, 30281 => 37694, 30282 => 37738, 30283 => 37834, + 30284 => 37775, 30285 => 37950, 30286 => 37995, 30287 => 40063, 30288 => 40066, + 30289 => 40069, 30290 => 40070, 30291 => 40071, 30292 => 40072, 30293 => 31267, + 30294 => 40075, 30295 => 40078, 30296 => 40080, 30297 => 40081, 30298 => 40082, + 30299 => 40084, 30300 => 40085, 30301 => 40090, 30302 => 40091, 30303 => 40094, + 30304 => 40095, 30305 => 40096, 30306 => 40097, 30307 => 40098, 30308 => 40099, + 30309 => 40101, 30310 => 40102, 30311 => 40103, 30312 => 40104, 30313 => 40105, + 30314 => 40107, 30315 => 40109, 30316 => 40110, 30317 => 40112, 30318 => 40113, + 30319 => 40114, 30320 => 40115, 30321 => 40116, 30322 => 40117, 30323 => 40118, + 30324 => 40119, 30325 => 40122, 30326 => 40123, 30327 => 40124, 30328 => 40125, + 30329 => 40132, 30330 => 40133, 30331 => 40134, 30332 => 40135, 30333 => 40138, + 30334 => 40139, 30497 => 40140, 30498 => 40141, 30499 => 40142, 30500 => 40143, + 30501 => 40144, 30502 => 40147, 30503 => 40148, 30504 => 40149, 30505 => 40151, + 30506 => 40152, 30507 => 40153, 30508 => 40156, 30509 => 40157, 30510 => 40159, + 30511 => 40162, 30512 => 38780, 30513 => 38789, 30514 => 38801, 30515 => 38802, + 30516 => 38804, 30517 => 38831, 30518 => 38827, 30519 => 38819, 30520 => 38834, + 30521 => 38836, 30522 => 39601, 30523 => 39600, 30524 => 39607, 30525 => 40536, + 30526 => 39606, 30527 => 39610, 30528 => 39612, 30529 => 39617, 30530 => 39616, + 30531 => 39621, 30532 => 39618, 30533 => 39627, 30534 => 39628, 30535 => 39633, + 30536 => 39749, 30537 => 39747, 30538 => 39751, 30539 => 39753, 30540 => 39752, + 30541 => 39757, 30542 => 39761, 30543 => 39144, 30544 => 39181, 30545 => 39214, + 30546 => 39253, 30547 => 39252, 30548 => 39647, 30549 => 39649, 30550 => 39654, + 30551 => 39663, 30552 => 39659, 30553 => 39675, 30554 => 39661, 30555 => 39673, + 30556 => 39688, 30557 => 39695, 30558 => 39699, 30559 => 39711, 30560 => 39715, + 30561 => 40637, 30562 => 40638, 30563 => 32315, 30564 => 40578, 30565 => 40583, + 30566 => 40584, 30567 => 40587, 30568 => 40594, 30569 => 37846, 30570 => 40605, + 30571 => 40607, 30572 => 40667, 30573 => 40668, 30574 => 40669, 30575 => 40672, + 30576 => 40671, 30577 => 40674, 30578 => 40681, 30579 => 40679, 30580 => 40677, + 30581 => 40682, 30582 => 40687, 30583 => 40738, 30584 => 40748, 30585 => 40751, + 30586 => 40761, 30587 => 40759, 30588 => 40765, 30589 => 40766, 30590 => 40772, + 0 => 0 ); + + function gb2utf8($gb) { + if( !trim($gb) ) return $gb; + $utf8=''; + while($gb) { + if( ord(substr($gb,0,1)) > 127 ) { + $t=substr($gb,0,2); + $gb=substr($gb,2); + $utf8 .= $this->u2utf8($this->codetable[hexdec(bin2hex($t))-0x8080]); + } + else { + $t=substr($gb,0,1); + $gb=substr($gb,1); + $utf8 .= $this->u2utf8($t); + } + } + return $utf8; + } + + function u2utf8($c) { + $str=''; + if ($c < 0x80) { + $str.=$c; + } + else if ($c < 0x800) { + $str.=chr(0xC0 | $c>>6); + $str.=chr(0x80 | $c & 0x3F); + } + else if ($c < 0x10000) { + $str.=chr(0xE0 | $c>>12); + $str.=chr(0x80 | $c>>6 & 0x3F); + $str.=chr(0x80 | $c & 0x3F); + } + else if ($c < 0x200000) { + $str.=chr(0xF0 | $c>>18); + $str.=chr(0x80 | $c>>12 & 0x3F); + $str.=chr(0x80 | $c>>6 & 0x3F); + $str.=chr(0x80 | $c & 0x3F); + } + return $str; + } + +} // END Class + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_gradient.php b/ext/jpgraph-3.0.7/src/jpgraph_gradient.php index a990b9f..b224b97 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_gradient.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_gradient.php @@ -1,434 +1,434 @@ -img = $img; - } - - - function SetNumColors($aNum) { - $this->numcolors=$aNum; - } - //--------------- - // PUBLIC METHODS - // Produce a gradient filled rectangle with a smooth transition between - // two colors. - // ($xl,$yt) Top left corner - // ($xr,$yb) Bottom right - // $from_color Starting color in gradient - // $to_color End color in the gradient - // $style Which way is the gradient oriented? - function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { - $this->img->SetLineWeight(1); - switch( $style ) { - case GRAD_VER: - $steps = ceil(abs($xr-$xl)+1); - $delta = $xr>=$xl ? 1 : -1; - $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); - for( $i=0, $x=$xl; $i < $steps; ++$i ) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yt,$x,$yb); - $x += $delta; - } - break; - - case GRAD_HOR: - $steps = ceil(abs($yb-$yt)+1); - $delta = $yb >= $yt ? 1 : -1; - $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); - for($i=0,$y=$yt; $i < $steps; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($xl,$y,$xr,$y); - $y += $delta; - } - break; - - case GRAD_MIDHOR: - $steps = ceil(abs($yb-$yt)/2); - $delta = $yb >= $yt ? 1 : -1; - $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); - for($y=$yt, $i=0; $i < $steps; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($xl,$y,$xr,$y); - $y += $delta; - } - --$i; - if( abs($yb-$yt) % 2 == 1 ) { - --$steps; - } - for($j=0; $j < $steps; ++$j, --$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($xl,$y,$xr,$y); - $y += $delta; - } - $this->img->Line($xl,$y,$xr,$y); - break; - - case GRAD_MIDVER: - $steps = ceil(abs($xr-$xl)/2); - $delta = $xr>=$xl ? 1 : -1; - $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); - for($x=$xl, $i=0; $i < $steps; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - --$i; - if( abs($xr-$xl) % 2 == 1 ) { - --$steps; - } - for($j=0; $j < $steps; ++$j, --$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - $this->img->Line($x,$yb,$x,$yt); - break; - - case GRAD_WIDE_MIDVER: - $diff = ceil(abs($xr-$xl)); - $steps = floor(abs($diff)/3); - $firststep = $diff - 2*$steps ; - $delta = $xr >= $xl ? 1 : -1; - $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); - for($x=$xl, $i=0; $i < $firststep; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - --$i; - $this->img->current_color = $colors[$i]; - for($j=0; $j< $steps; ++$j) { - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - - for($j=0; $j < $steps; ++$j, --$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - break; - - case GRAD_WIDE_MIDHOR: - $diff = ceil(abs($yb-$yt)); - $steps = floor(abs($diff)/3); - $firststep = $diff - 2*$steps ; - $delta = $yb >= $yt? 1 : -1; - $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); - for($y=$yt, $i=0; $i < $firststep; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($xl,$y,$xr,$y); - $y += $delta; - } - --$i; - $this->img->current_color = $colors[$i]; - for($j=0; $j < $steps; ++$j) { - $this->img->Line($xl,$y,$xr,$y); - $y += $delta; - } - for($j=0; $j < $steps; ++$j, --$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($xl,$y,$xr,$y); - $y += $delta; - } - break; - - case GRAD_LEFT_REFLECTION: - $steps1 = ceil(0.3*abs($xr-$xl)); - $delta = $xr>=$xl ? 1 : -1; - - $from_color = $this->img->rgb->Color($from_color); - $adj = 1.4; - $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); - $from_color2 = array(min(255,$from_color[0]+$m), - min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); - - $this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors); - $n = count($colors); - for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - $steps2 = max(1,ceil(0.08*abs($xr-$xl))); - $this->img->SetColor($to_color); - for($j=0; $j< $steps2; ++$j) { - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - $steps = abs($xr-$xl)-$steps1-$steps2; - $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); - $n = count($colors); - for($i=0; $i < $steps && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - break; - - case GRAD_RIGHT_REFLECTION: - $steps1 = ceil(0.7*abs($xr-$xl)); - $delta = $xr>=$xl ? 1 : -1; - - $this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors); - $n = count($colors); - for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - $steps2 = max(1,ceil(0.08*abs($xr-$xl))); - $this->img->SetColor($to_color); - for($j=0; $j< $steps2; ++$j) { - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - - $from_color = $this->img->rgb->Color($from_color); - $adj = 1.4; - $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); - $from_color = array(min(255,$from_color[0]+$m), - min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); - - $steps = abs($xr-$xl)-$steps1-$steps2; - $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); - $n = count($colors); - for($i=0; $i < $steps && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - break; - - case GRAD_CENTER: - $steps = ceil(min(($yb-$yt)+1,($xr-$xl)+1)/2); - $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); - $dx = ($xr-$xl)/2; - $dy = ($yb-$yt)/2; - $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; - $n = count($colors); - for($x=$xl, $i=0; $x < $xl+$dx && $y < $yt+$dy && $i < $n; ++$x, ++$y, --$x2, --$y2, ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Rectangle($x,$y,$x2,$y2); - } - $this->img->Line($x,$y,$x2,$y2); - break; - - case GRAD_RAISED_PANEL: - // right to left - $steps1 = $xr-$xl; - $delta = $xr>=$xl ? 1 : -1; - $this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors); - $n = count($colors); - for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - - // left to right - $xr -= 3; - $xl += 3; - $yb -= 3; - $yt += 3; - $steps2 = $xr-$xl; - $delta = $xr>=$xl ? 1 : -1; - for($x=$xl, $j=$steps2; $j >= 0; --$j) { - $this->img->current_color = $colors[$j]; - $this->img->Line($x,$yb,$x,$yt); - $x += $delta; - } - break; - - case GRAD_DIAGONAL: - // use the longer dimension to determine the required number of steps. - // first loop draws from one corner to the mid-diagonal and the second - // loop draws from the mid-diagonal to the opposing corner. - if($xr-$xl > $yb - $yt) { - // width is greater than height -> use x-dimension for steps - $steps = $xr-$xl; - $delta = $xr>=$xl ? 1 : -1; - $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors); - $n = count($colors); - - for($x=$xl, $i=0; $i < $steps && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $y = $yt+($i/$steps)*($yb-$yt)*$delta; - $this->img->Line($x,$yt,$xl,$y); - $x += $delta; - } - - for($x=$xl, $i = 0; $i < $steps && $i < $n; ++$i) { - $this->img->current_color = $colors[$steps+$i]; - $y = $yt+($i/$steps)*($yb-$yt)*$delta; - $this->img->Line($x,$yb,$xr,$y); - $x += $delta; - } - } else { - // height is greater than width -> use y-dimension for steps - $steps = $yb-$yt; - $delta = $yb>=$yt ? 1 : -1; - $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors); - $n = count($colors); - - for($y=$yt, $i=0; $i < $steps && $i < $n; ++$i) { - $this->img->current_color = $colors[$i]; - $x = $xl+($i/$steps)*($xr-$xl)*$delta; - $this->img->Line($x,$yt,$xl,$y); - $y += $delta; - } - - for($y=$yt, $i = 0; $i < $steps && $i < $n; ++$i) { - $this->img->current_color = $colors[$steps+$i]; - $x = $xl+($i/$steps)*($xr-$xl)*$delta; - $this->img->Line($x,$yb,$xr,$y); - $x += $delta; - } - - } - break; - - default: - JpGraphError::RaiseL(7001,$style); - //("Unknown gradient style (=$style)."); - break; - } - } - - // Fill a special case of a polygon with a flat bottom - // with a gradient. Can be used for filled line plots. - // Please note that this is NOT a generic gradient polygon fill - // routine. It assumes that the bottom is flat (like a drawing - // of a mountain) - function FilledFlatPolygon($pts,$from_color,$to_color) { - if( count($pts) == 0 ) return; - - $maxy=$pts[1]; - $miny=$pts[1]; - $n = count($pts) ; - for( $i=0, $idx=0; $i < $n; $i += 2) { - $x = round($pts[$i]); - $y = round($pts[$i+1]); - $miny = min($miny,$y); - $maxy = max($maxy,$y); - } - - $colors = array(); - $this->GetColArray($from_color,$to_color,abs($maxy-$miny)+1,$colors,$this->numcolors); - for($i=$miny, $idx=0; $i <= $maxy; ++$i ) { - $colmap[$i] = $colors[$idx++]; - } - - $n = count($pts)/2 ; - $idx = 0 ; - while( $idx < $n-1 ) { - $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+1])); - $p2 = array(round($pts[++$idx*2]),round($pts[$idx*2+1])); - - // Find the largest rectangle we can fill - $y = max($p1[1],$p2[1]) ; - for($yy=$maxy; $yy > $y; --$yy) { - $this->img->current_color = $colmap[$yy]; - $this->img->Line($p1[0],$yy,$p2[0]-1,$yy); - } - - if( $p1[1] == $p2[1] ) { - continue; - } - - // Fill the rest using lines (slow...) - $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]); - $x1 = $p1[0]; - $x2 = $p2[0]-1; - $start = $y; - if( $p1[1] > $p2[1] ) { - while( $y >= $p2[1] ) { - $x1=$slope*($start-$y)+$p1[0]; - $this->img->current_color = $colmap[$y]; - $this->img->Line($x1,$y,$x2,$y); - --$y; - } - } - else { - while( $y >= $p1[1] ) { - $x2=$p2[0]+$slope*($start-$y); - $this->img->current_color = $colmap[$y]; - $this->img->Line($x1,$y,$x2,$y); - --$y; - } - } - } - } - - //--------------- - // PRIVATE METHODS - // Add to the image color map the necessary colors to do the transition - // between the two colors using $numcolors intermediate colors - function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { - if( $arr_size==0 ) { - return; - } - - // If color is given as text get it's corresponding r,g,b values - $from_color = $this->img->rgb->Color($from_color); - $to_color = $this->img->rgb->Color($to_color); - - $rdelta=($to_color[0]-$from_color[0])/$numcols; - $gdelta=($to_color[1]-$from_color[1])/$numcols; - $bdelta=($to_color[2]-$from_color[2])/$numcols; - $colorsperstep = $numcols/$arr_size; - $prevcolnum = -1; - $from_alpha = $from_color[3]; - $to_alpha = $to_color[3]; - $adelta = ( $to_alpha - $from_alpha ) / $numcols ; - for ($i=0; $i < $arr_size; ++$i) { - $colnum = floor($colorsperstep*$i); - if ( $colnum == $prevcolnum ) { - $colors[$i] = $colidx; - } - else { - $r = floor($from_color[0] + $colnum*$rdelta); - $g = floor($from_color[1] + $colnum*$gdelta); - $b = floor($from_color[2] + $colnum*$bdelta); - $alpha = $from_alpha + $colnum*$adelta; - $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b),$alpha); - $colors[$i] = $colidx; - } - $prevcolnum = $colnum; - } - } -} // Class - -?> +img = $img; + } + + + function SetNumColors($aNum) { + $this->numcolors=$aNum; + } + //--------------- + // PUBLIC METHODS + // Produce a gradient filled rectangle with a smooth transition between + // two colors. + // ($xl,$yt) Top left corner + // ($xr,$yb) Bottom right + // $from_color Starting color in gradient + // $to_color End color in the gradient + // $style Which way is the gradient oriented? + function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { + $this->img->SetLineWeight(1); + switch( $style ) { + case GRAD_VER: + $steps = ceil(abs($xr-$xl)+1); + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for( $i=0, $x=$xl; $i < $steps; ++$i ) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yt,$x,$yb); + $x += $delta; + } + break; + + case GRAD_HOR: + $steps = ceil(abs($yb-$yt)+1); + $delta = $yb >= $yt ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for($i=0,$y=$yt; $i < $steps; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + break; + + case GRAD_MIDHOR: + $steps = ceil(abs($yb-$yt)/2); + $delta = $yb >= $yt ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for($y=$yt, $i=0; $i < $steps; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + --$i; + if( abs($yb-$yt) % 2 == 1 ) { + --$steps; + } + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + $this->img->Line($xl,$y,$xr,$y); + break; + + case GRAD_MIDVER: + $steps = ceil(abs($xr-$xl)/2); + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for($x=$xl, $i=0; $i < $steps; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + --$i; + if( abs($xr-$xl) % 2 == 1 ) { + --$steps; + } + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $this->img->Line($x,$yb,$x,$yt); + break; + + case GRAD_WIDE_MIDVER: + $diff = ceil(abs($xr-$xl)); + $steps = floor(abs($diff)/3); + $firststep = $diff - 2*$steps ; + $delta = $xr >= $xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); + for($x=$xl, $i=0; $i < $firststep; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + --$i; + $this->img->current_color = $colors[$i]; + for($j=0; $j< $steps; ++$j) { + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_WIDE_MIDHOR: + $diff = ceil(abs($yb-$yt)); + $steps = floor(abs($diff)/3); + $firststep = $diff - 2*$steps ; + $delta = $yb >= $yt? 1 : -1; + $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); + for($y=$yt, $i=0; $i < $firststep; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + --$i; + $this->img->current_color = $colors[$i]; + for($j=0; $j < $steps; ++$j) { + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + break; + + case GRAD_LEFT_REFLECTION: + $steps1 = ceil(0.3*abs($xr-$xl)); + $delta = $xr>=$xl ? 1 : -1; + + $from_color = $this->img->rgb->Color($from_color); + $adj = 1.4; + $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); + $from_color2 = array(min(255,$from_color[0]+$m), + min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); + + $this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors); + $n = count($colors); + for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $steps2 = max(1,ceil(0.08*abs($xr-$xl))); + $this->img->SetColor($to_color); + for($j=0; $j< $steps2; ++$j) { + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $steps = abs($xr-$xl)-$steps1-$steps2; + $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); + $n = count($colors); + for($i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_RIGHT_REFLECTION: + $steps1 = ceil(0.7*abs($xr-$xl)); + $delta = $xr>=$xl ? 1 : -1; + + $this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors); + $n = count($colors); + for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $steps2 = max(1,ceil(0.08*abs($xr-$xl))); + $this->img->SetColor($to_color); + for($j=0; $j< $steps2; ++$j) { + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + + $from_color = $this->img->rgb->Color($from_color); + $adj = 1.4; + $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); + $from_color = array(min(255,$from_color[0]+$m), + min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); + + $steps = abs($xr-$xl)-$steps1-$steps2; + $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); + $n = count($colors); + for($i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_CENTER: + $steps = ceil(min(($yb-$yt)+1,($xr-$xl)+1)/2); + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + $dx = ($xr-$xl)/2; + $dy = ($yb-$yt)/2; + $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; + $n = count($colors); + for($x=$xl, $i=0; $x < $xl+$dx && $y < $yt+$dy && $i < $n; ++$x, ++$y, --$x2, --$y2, ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Rectangle($x,$y,$x2,$y2); + } + $this->img->Line($x,$y,$x2,$y2); + break; + + case GRAD_RAISED_PANEL: + // right to left + $steps1 = $xr-$xl; + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors); + $n = count($colors); + for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + + // left to right + $xr -= 3; + $xl += 3; + $yb -= 3; + $yt += 3; + $steps2 = $xr-$xl; + $delta = $xr>=$xl ? 1 : -1; + for($x=$xl, $j=$steps2; $j >= 0; --$j) { + $this->img->current_color = $colors[$j]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_DIAGONAL: + // use the longer dimension to determine the required number of steps. + // first loop draws from one corner to the mid-diagonal and the second + // loop draws from the mid-diagonal to the opposing corner. + if($xr-$xl > $yb - $yt) { + // width is greater than height -> use x-dimension for steps + $steps = $xr-$xl; + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors); + $n = count($colors); + + for($x=$xl, $i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $y = $yt+($i/$steps)*($yb-$yt)*$delta; + $this->img->Line($x,$yt,$xl,$y); + $x += $delta; + } + + for($x=$xl, $i = 0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$steps+$i]; + $y = $yt+($i/$steps)*($yb-$yt)*$delta; + $this->img->Line($x,$yb,$xr,$y); + $x += $delta; + } + } else { + // height is greater than width -> use y-dimension for steps + $steps = $yb-$yt; + $delta = $yb>=$yt ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors); + $n = count($colors); + + for($y=$yt, $i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $x = $xl+($i/$steps)*($xr-$xl)*$delta; + $this->img->Line($x,$yt,$xl,$y); + $y += $delta; + } + + for($y=$yt, $i = 0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$steps+$i]; + $x = $xl+($i/$steps)*($xr-$xl)*$delta; + $this->img->Line($x,$yb,$xr,$y); + $x += $delta; + } + + } + break; + + default: + JpGraphError::RaiseL(7001,$style); + //("Unknown gradient style (=$style)."); + break; + } + } + + // Fill a special case of a polygon with a flat bottom + // with a gradient. Can be used for filled line plots. + // Please note that this is NOT a generic gradient polygon fill + // routine. It assumes that the bottom is flat (like a drawing + // of a mountain) + function FilledFlatPolygon($pts,$from_color,$to_color) { + if( count($pts) == 0 ) return; + + $maxy=$pts[1]; + $miny=$pts[1]; + $n = count($pts) ; + for( $i=0, $idx=0; $i < $n; $i += 2) { + $x = round($pts[$i]); + $y = round($pts[$i+1]); + $miny = min($miny,$y); + $maxy = max($maxy,$y); + } + + $colors = array(); + $this->GetColArray($from_color,$to_color,abs($maxy-$miny)+1,$colors,$this->numcolors); + for($i=$miny, $idx=0; $i <= $maxy; ++$i ) { + $colmap[$i] = $colors[$idx++]; + } + + $n = count($pts)/2 ; + $idx = 0 ; + while( $idx < $n-1 ) { + $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+1])); + $p2 = array(round($pts[++$idx*2]),round($pts[$idx*2+1])); + + // Find the largest rectangle we can fill + $y = max($p1[1],$p2[1]) ; + for($yy=$maxy; $yy > $y; --$yy) { + $this->img->current_color = $colmap[$yy]; + $this->img->Line($p1[0],$yy,$p2[0]-1,$yy); + } + + if( $p1[1] == $p2[1] ) { + continue; + } + + // Fill the rest using lines (slow...) + $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]); + $x1 = $p1[0]; + $x2 = $p2[0]-1; + $start = $y; + if( $p1[1] > $p2[1] ) { + while( $y >= $p2[1] ) { + $x1=$slope*($start-$y)+$p1[0]; + $this->img->current_color = $colmap[$y]; + $this->img->Line($x1,$y,$x2,$y); + --$y; + } + } + else { + while( $y >= $p1[1] ) { + $x2=$p2[0]+$slope*($start-$y); + $this->img->current_color = $colmap[$y]; + $this->img->Line($x1,$y,$x2,$y); + --$y; + } + } + } + } + + //--------------- + // PRIVATE METHODS + // Add to the image color map the necessary colors to do the transition + // between the two colors using $numcolors intermediate colors + function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { + if( $arr_size==0 ) { + return; + } + + // If color is given as text get it's corresponding r,g,b values + $from_color = $this->img->rgb->Color($from_color); + $to_color = $this->img->rgb->Color($to_color); + + $rdelta=($to_color[0]-$from_color[0])/$numcols; + $gdelta=($to_color[1]-$from_color[1])/$numcols; + $bdelta=($to_color[2]-$from_color[2])/$numcols; + $colorsperstep = $numcols/$arr_size; + $prevcolnum = -1; + $from_alpha = $from_color[3]; + $to_alpha = $to_color[3]; + $adelta = ( $to_alpha - $from_alpha ) / $numcols ; + for ($i=0; $i < $arr_size; ++$i) { + $colnum = floor($colorsperstep*$i); + if ( $colnum == $prevcolnum ) { + $colors[$i] = $colidx; + } + else { + $r = floor($from_color[0] + $colnum*$rdelta); + $g = floor($from_color[1] + $colnum*$gdelta); + $b = floor($from_color[2] + $colnum*$bdelta); + $alpha = $from_alpha + $colnum*$adelta; + $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b),$alpha); + $colors[$i] = $colidx; + } + $prevcolnum = $colnum; + } + } +} // Class + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_iconplot.php b/ext/jpgraph-3.0.7/src/jpgraph_iconplot.php index ca62231..f3dc1cb 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_iconplot.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_iconplot.php @@ -1,190 +1,190 @@ -iFile = $aFile; - $this->iX=$aX; - $this->iY=$aY; - $this->iScale= $aScale; - if( $aMix < 0 || $aMix > 100 ) { - JpGraphError::RaiseL(8001); //('Mix value for icon must be between 0 and 100.'); - } - $this->iMix = $aMix ; - } - - function SetCountryFlag($aFlag,$aX=0,$aY=0,$aScale=1.0,$aMix=100,$aStdSize=3) { - $this->iCountryFlag = $aFlag; - $this->iX=$aX; - $this->iY=$aY; - $this->iScale= $aScale; - if( $aMix < 0 || $aMix > 100 ) { - JpGraphError::RaiseL(8001);//'Mix value for icon must be between 0 and 100.'); - } - $this->iMix = $aMix; - $this->iCountryStdSize = $aStdSize; - } - - function SetPos($aX,$aY) { - $this->iX=$aX; - $this->iY=$aY; - } - - function CreateFromString($aStr) { - $this->iImgString = $aStr; - } - - function SetScalePos($aX,$aY) { - $this->iScalePosX = $aX; - $this->iScalePosY = $aY; - } - - function SetScale($aScale) { - $this->iScale = $aScale; - } - - function SetMix($aMix) { - if( $aMix < 0 || $aMix > 100 ) { - JpGraphError::RaiseL(8001);//('Mix value for icon must be between 0 and 100.'); - } - $this->iMix = $aMix ; - } - - function SetAnchor($aXAnchor='left',$aYAnchor='center') { - if( !in_array($aXAnchor,$this->iAnchors) || - !in_array($aYAnchor,$this->iAnchors) ) { - JpGraphError::RaiseL(8002);//("Anchor position for icons must be one of 'top', 'bottom', 'left', 'right' or 'center'"); - } - $this->iHorAnchor=$aXAnchor; - $this->iVertAnchor=$aYAnchor; - } - - function PreStrokeAdjust($aGraph) { - // Nothing to do ... - } - - function DoLegend($aGraph) { - // Nothing to do ... - } - - function Max() { - return array(false,false); - } - - - // The next four function are framework function tht gets called - // from Gantt and is not menaiungfull in the context of Icons but - // they must be implemented to avoid errors. - function GetMaxDate() { return false; } - function GetMinDate() { return false; } - function GetLineNbr() { return 0; } - function GetAbsHeight() {return 0; } - - - function Min() { - return array(false,false); - } - - function StrokeMargin(&$aImg) { - return true; - } - - function Stroke($aImg,$axscale=null,$ayscale=null) { - $this->StrokeWithScale($aImg,$axscale,$ayscale); - } - - function StrokeWithScale($aImg,$axscale,$ayscale) { - if( $this->iScalePosX === null || $this->iScalePosY === null || - $axscale === null || $ayscale === null ) { - $this->_Stroke($aImg); - } - else { - $this->_Stroke($aImg, - round($axscale->Translate($this->iScalePosX)), - round($ayscale->Translate($this->iScalePosY))); - } - } - - function GetWidthHeight() { - $dummy=0; - return $this->_Stroke($dummy,null,null,true); - } - - function _Stroke($aImg,$x=null,$y=null,$aReturnWidthHeight=false) { - if( $this->iFile != '' && $this->iCountryFlag != '' ) { - JpGraphError::RaiseL(8003);//('It is not possible to specify both an image file and a country flag for the same icon.'); - } - if( $this->iFile != '' ) { - $gdimg = Graph::LoadBkgImage('',$this->iFile); - } - elseif( $this->iImgString != '') { - $gdimg = Image::CreateFromString($this->iImgString); - } - - else { - if( ! class_exists('FlagImages',false) ) { - JpGraphError::RaiseL(8004);//('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.'); - } - $fobj = new FlagImages($this->iCountryStdSize); - $dummy=''; - $gdimg = $fobj->GetImgByName($this->iCountryFlag,$dummy); - } - - $iconw = imagesx($gdimg); - $iconh = imagesy($gdimg); - - if( $aReturnWidthHeight ) { - return array(round($iconw*$this->iScale),round($iconh*$this->iScale)); - } - - if( $x !== null && $y !== null ) { - $this->iX = $x; $this->iY = $y; - } - if( $this->iX >= 0 && $this->iX <= 1.0 ) { - $w = imagesx($aImg->img); - $this->iX = round($w*$this->iX); - } - if( $this->iY >= 0 && $this->iY <= 1.0 ) { - $h = imagesy($aImg->img); - $this->iY = round($h*$this->iY); - } - - if( $this->iHorAnchor == 'center' ) - $this->iX -= round($iconw*$this->iScale/2); - if( $this->iHorAnchor == 'right' ) - $this->iX -= round($iconw*$this->iScale); - if( $this->iVertAnchor == 'center' ) - $this->iY -= round($iconh*$this->iScale/2); - if( $this->iVertAnchor == 'bottom' ) - $this->iY -= round($iconh*$this->iScale); - - $aImg->CopyMerge($gdimg,$this->iX,$this->iY,0,0, - round($iconw*$this->iScale),round($iconh*$this->iScale), - $iconw,$iconh, - $this->iMix); - } -} - -?> +iFile = $aFile; + $this->iX=$aX; + $this->iY=$aY; + $this->iScale= $aScale; + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001); //('Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix ; + } + + function SetCountryFlag($aFlag,$aX=0,$aY=0,$aScale=1.0,$aMix=100,$aStdSize=3) { + $this->iCountryFlag = $aFlag; + $this->iX=$aX; + $this->iY=$aY; + $this->iScale= $aScale; + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001);//'Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix; + $this->iCountryStdSize = $aStdSize; + } + + function SetPos($aX,$aY) { + $this->iX=$aX; + $this->iY=$aY; + } + + function CreateFromString($aStr) { + $this->iImgString = $aStr; + } + + function SetScalePos($aX,$aY) { + $this->iScalePosX = $aX; + $this->iScalePosY = $aY; + } + + function SetScale($aScale) { + $this->iScale = $aScale; + } + + function SetMix($aMix) { + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001);//('Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix ; + } + + function SetAnchor($aXAnchor='left',$aYAnchor='center') { + if( !in_array($aXAnchor,$this->iAnchors) || + !in_array($aYAnchor,$this->iAnchors) ) { + JpGraphError::RaiseL(8002);//("Anchor position for icons must be one of 'top', 'bottom', 'left', 'right' or 'center'"); + } + $this->iHorAnchor=$aXAnchor; + $this->iVertAnchor=$aYAnchor; + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do ... + } + + function DoLegend($aGraph) { + // Nothing to do ... + } + + function Max() { + return array(false,false); + } + + + // The next four function are framework function tht gets called + // from Gantt and is not menaiungfull in the context of Icons but + // they must be implemented to avoid errors. + function GetMaxDate() { return false; } + function GetMinDate() { return false; } + function GetLineNbr() { return 0; } + function GetAbsHeight() {return 0; } + + + function Min() { + return array(false,false); + } + + function StrokeMargin(&$aImg) { + return true; + } + + function Stroke($aImg,$axscale=null,$ayscale=null) { + $this->StrokeWithScale($aImg,$axscale,$ayscale); + } + + function StrokeWithScale($aImg,$axscale,$ayscale) { + if( $this->iScalePosX === null || $this->iScalePosY === null || + $axscale === null || $ayscale === null ) { + $this->_Stroke($aImg); + } + else { + $this->_Stroke($aImg, + round($axscale->Translate($this->iScalePosX)), + round($ayscale->Translate($this->iScalePosY))); + } + } + + function GetWidthHeight() { + $dummy=0; + return $this->_Stroke($dummy,null,null,true); + } + + function _Stroke($aImg,$x=null,$y=null,$aReturnWidthHeight=false) { + if( $this->iFile != '' && $this->iCountryFlag != '' ) { + JpGraphError::RaiseL(8003);//('It is not possible to specify both an image file and a country flag for the same icon.'); + } + if( $this->iFile != '' ) { + $gdimg = Graph::LoadBkgImage('',$this->iFile); + } + elseif( $this->iImgString != '') { + $gdimg = Image::CreateFromString($this->iImgString); + } + + else { + if( ! class_exists('FlagImages',false) ) { + JpGraphError::RaiseL(8004);//('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.'); + } + $fobj = new FlagImages($this->iCountryStdSize); + $dummy=''; + $gdimg = $fobj->GetImgByName($this->iCountryFlag,$dummy); + } + + $iconw = imagesx($gdimg); + $iconh = imagesy($gdimg); + + if( $aReturnWidthHeight ) { + return array(round($iconw*$this->iScale),round($iconh*$this->iScale)); + } + + if( $x !== null && $y !== null ) { + $this->iX = $x; $this->iY = $y; + } + if( $this->iX >= 0 && $this->iX <= 1.0 ) { + $w = imagesx($aImg->img); + $this->iX = round($w*$this->iX); + } + if( $this->iY >= 0 && $this->iY <= 1.0 ) { + $h = imagesy($aImg->img); + $this->iY = round($h*$this->iY); + } + + if( $this->iHorAnchor == 'center' ) + $this->iX -= round($iconw*$this->iScale/2); + if( $this->iHorAnchor == 'right' ) + $this->iX -= round($iconw*$this->iScale); + if( $this->iVertAnchor == 'center' ) + $this->iY -= round($iconh*$this->iScale/2); + if( $this->iVertAnchor == 'bottom' ) + $this->iY -= round($iconh*$this->iScale); + + $aImg->CopyMerge($gdimg,$this->iX,$this->iY,0,0, + round($iconw*$this->iScale),round($iconh*$this->iScale), + $iconw,$iconh, + $this->iMix); + } +} + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_imgtrans.php b/ext/jpgraph-3.0.7/src/jpgraph_imgtrans.php index 6f0cc07..af152bc 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_imgtrans.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_imgtrans.php @@ -1,223 +1,223 @@ -gdImg = $aGdImg; - } - - // -------------------------------------------------------------------- - // _TransVert3D() and _TransHor3D() are helper methods to - // Skew3D(). - // -------------------------------------------------------------------- - function _TransVert3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_DOWN,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { - - - // Parameter check - if( $aHorizonPos < 0 || $aHorizonPos > 1.0 ) { - JpGraphError::RaiseL(9001); - //("Value for image transformation out of bounds.\nVanishing point on horizon must be specified as a value between 0 and 1."); - } - - $w = imagesx($aGdImg); - $h = imagesy($aGdImg); - - // Create new image - $ww = $w; - if( $aMinSize ) - $hh = ceil($h * $aHorizon / ($aSkewDist+$h)); - else - $hh = $h; - - $newgdh = imagecreatetruecolor($ww,$hh); - $crgb = new RGB( $newgdh ); - $fillColor = $crgb->Allocate($aFillColor); - imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); - - if( $aBorder ) { - $colidx = $crgb->Allocate($aBorder); - imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); - } - - $mid = round($w * $aHorizonPos); - - $last=$h; - for($y=0; $y < $h; ++$y) { - - $yp = $h-$y-1; - $yt = floor($yp * $aHorizon / ($aSkewDist + $yp)); - - if( !$aQuality ) { - if( $last <= $yt ) continue ; - $last = $yt; - } - - for($x=0; $x < $w; ++$x) { - $xt = ($x-$mid) * $aSkewDist / ($aSkewDist + $yp); - if( $aDir == SKEW3D_UP ) - $rgb = imagecolorat($aGdImg,$x,$h-$y-1); - else - $rgb = imagecolorat($aGdImg,$x,$y); - $r = ($rgb >> 16) & 0xFF; - $g = ($rgb >> 8) & 0xFF; - $b = $rgb & 0xFF; - $colidx = imagecolorallocate($newgdh,$r,$g,$b); - $xt = round($xt+$mid); - if( $aDir == SKEW3D_UP ) { - $syt = $yt; - } - else { - $syt = $hh-$yt-1; - } - - if( !empty($set[$yt]) ) { - $nrgb = imagecolorat($newgdh,$xt,$syt); - $nr = ($nrgb >> 16) & 0xFF; - $ng = ($nrgb >> 8) & 0xFF; - $nb = $nrgb & 0xFF; - $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), - floor(($g+$ng)/2),floor(($b+$nb)/2)); - } - - imagesetpixel($newgdh,$xt,$syt,$colidx); - } - - $set[$yt] = true; - } - - return $newgdh; - } - - // -------------------------------------------------------------------- - // _TransVert3D() and _TransHor3D() are helper methods to - // Skew3D(). - // -------------------------------------------------------------------- - function _TransHor3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_LEFT,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { - - $w = imagesx($aGdImg); - $h = imagesy($aGdImg); - - // Create new image - $hh = $h; - if( $aMinSize ) - $ww = ceil($w * $aHorizon / ($aSkewDist+$w)); - else - $ww = $w; - - $newgdh = imagecreatetruecolor($ww,$hh); - $crgb = new RGB( $newgdh ); - $fillColor = $crgb->Allocate($aFillColor); - imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); - - if( $aBorder ) { - $colidx = $crgb->Allocate($aBorder); - imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); - } - - $mid = round($h * $aHorizonPos); - - $last = -1; - for($x=0; $x < $w-1; ++$x) { - $xt = floor($x * $aHorizon / ($aSkewDist + $x)); - if( !$aQuality ) { - if( $last >= $xt ) continue ; - $last = $xt; - } - - for($y=0; $y < $h; ++$y) { - $yp = $h-$y-1; - $yt = ($yp-$mid) * $aSkewDist / ($aSkewDist + $x); - - if( $aDir == SKEW3D_RIGHT ) - $rgb = imagecolorat($aGdImg,$w-$x-1,$y); - else - $rgb = imagecolorat($aGdImg,$x,$y); - $r = ($rgb >> 16) & 0xFF; - $g = ($rgb >> 8) & 0xFF; - $b = $rgb & 0xFF; - $colidx = imagecolorallocate($newgdh,$r,$g,$b); - $yt = floor($hh-$yt-$mid-1); - if( $aDir == SKEW3D_RIGHT ) { - $sxt = $ww-$xt-1; - } - else - $sxt = $xt ; - - if( !empty($set[$xt]) ) { - $nrgb = imagecolorat($newgdh,$sxt,$yt); - $nr = ($nrgb >> 16) & 0xFF; - $ng = ($nrgb >> 8) & 0xFF; - $nb = $nrgb & 0xFF; - $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), - floor(($g+$ng)/2),floor(($b+$nb)/2)); - } - imagesetpixel($newgdh,$sxt,$yt,$colidx); - } - - $set[$xt] = true; - } - - return $newgdh; - } - - // -------------------------------------------------------------------- - // Skew image for the apperance of a 3D effect - // This transforms an image into a 3D-skewed version - // of the image. The transformation is specified by giving the height - // of the artificial horizon and specifying a "skew" factor which - // is the distance on the horizon line between the point of - // convergence and perspective line. - // - // The function returns the GD handle of the transformed image - // leaving the original image untouched. - // - // Parameters: - // * $aGdImg, GD handle to the image to be transformed - // * $aHorizon, Distance to the horizon - // * $aSkewDist, Distance from the horizon point of convergence - // on the horizon line to the perspective points. A larger - // value will fore-shorten the image more - // * $aDir, parameter specifies type of convergence. This of this - // as the walls in a room you are looking at. This specifies if the - // image should be applied on the left,right,top or bottom walls. - // * $aMinSize, true=make the new image just as big as needed, - // false = keep the image the same size as the original image - // * $aFillColor, Background fill color in the image - // * $aHiQuality, true=performa some interpolation that improves - // the image quality but at the expense of performace. Enabling - // high quality will have a dramatic effect on the time it takes - // to transform an image. - // * $aBorder, if set to anything besides false this will draw a - // a border of the speciied color around the image - // -------------------------------------------------------------------- - function Skew3D($aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { - return $this->_Skew3D($this->gdImg,$aHorizon,$aSkewDist,$aDir,$aHiQuality, - $aMinSize,$aFillColor,$aBorder); - } - - function _Skew3D($aGdImg,$aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { - if( $aDir == SKEW3D_DOWN || $aDir == SKEW3D_UP ) - return $this->_TransVert3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); - else - return $this->_TransHor3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); - - } - -} - - +gdImg = $aGdImg; + } + + // -------------------------------------------------------------------- + // _TransVert3D() and _TransHor3D() are helper methods to + // Skew3D(). + // -------------------------------------------------------------------- + function _TransVert3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_DOWN,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { + + + // Parameter check + if( $aHorizonPos < 0 || $aHorizonPos > 1.0 ) { + JpGraphError::RaiseL(9001); + //("Value for image transformation out of bounds.\nVanishing point on horizon must be specified as a value between 0 and 1."); + } + + $w = imagesx($aGdImg); + $h = imagesy($aGdImg); + + // Create new image + $ww = $w; + if( $aMinSize ) + $hh = ceil($h * $aHorizon / ($aSkewDist+$h)); + else + $hh = $h; + + $newgdh = imagecreatetruecolor($ww,$hh); + $crgb = new RGB( $newgdh ); + $fillColor = $crgb->Allocate($aFillColor); + imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); + + if( $aBorder ) { + $colidx = $crgb->Allocate($aBorder); + imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); + } + + $mid = round($w * $aHorizonPos); + + $last=$h; + for($y=0; $y < $h; ++$y) { + + $yp = $h-$y-1; + $yt = floor($yp * $aHorizon / ($aSkewDist + $yp)); + + if( !$aQuality ) { + if( $last <= $yt ) continue ; + $last = $yt; + } + + for($x=0; $x < $w; ++$x) { + $xt = ($x-$mid) * $aSkewDist / ($aSkewDist + $yp); + if( $aDir == SKEW3D_UP ) + $rgb = imagecolorat($aGdImg,$x,$h-$y-1); + else + $rgb = imagecolorat($aGdImg,$x,$y); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $colidx = imagecolorallocate($newgdh,$r,$g,$b); + $xt = round($xt+$mid); + if( $aDir == SKEW3D_UP ) { + $syt = $yt; + } + else { + $syt = $hh-$yt-1; + } + + if( !empty($set[$yt]) ) { + $nrgb = imagecolorat($newgdh,$xt,$syt); + $nr = ($nrgb >> 16) & 0xFF; + $ng = ($nrgb >> 8) & 0xFF; + $nb = $nrgb & 0xFF; + $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), + floor(($g+$ng)/2),floor(($b+$nb)/2)); + } + + imagesetpixel($newgdh,$xt,$syt,$colidx); + } + + $set[$yt] = true; + } + + return $newgdh; + } + + // -------------------------------------------------------------------- + // _TransVert3D() and _TransHor3D() are helper methods to + // Skew3D(). + // -------------------------------------------------------------------- + function _TransHor3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_LEFT,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { + + $w = imagesx($aGdImg); + $h = imagesy($aGdImg); + + // Create new image + $hh = $h; + if( $aMinSize ) + $ww = ceil($w * $aHorizon / ($aSkewDist+$w)); + else + $ww = $w; + + $newgdh = imagecreatetruecolor($ww,$hh); + $crgb = new RGB( $newgdh ); + $fillColor = $crgb->Allocate($aFillColor); + imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); + + if( $aBorder ) { + $colidx = $crgb->Allocate($aBorder); + imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); + } + + $mid = round($h * $aHorizonPos); + + $last = -1; + for($x=0; $x < $w-1; ++$x) { + $xt = floor($x * $aHorizon / ($aSkewDist + $x)); + if( !$aQuality ) { + if( $last >= $xt ) continue ; + $last = $xt; + } + + for($y=0; $y < $h; ++$y) { + $yp = $h-$y-1; + $yt = ($yp-$mid) * $aSkewDist / ($aSkewDist + $x); + + if( $aDir == SKEW3D_RIGHT ) + $rgb = imagecolorat($aGdImg,$w-$x-1,$y); + else + $rgb = imagecolorat($aGdImg,$x,$y); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $colidx = imagecolorallocate($newgdh,$r,$g,$b); + $yt = floor($hh-$yt-$mid-1); + if( $aDir == SKEW3D_RIGHT ) { + $sxt = $ww-$xt-1; + } + else + $sxt = $xt ; + + if( !empty($set[$xt]) ) { + $nrgb = imagecolorat($newgdh,$sxt,$yt); + $nr = ($nrgb >> 16) & 0xFF; + $ng = ($nrgb >> 8) & 0xFF; + $nb = $nrgb & 0xFF; + $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), + floor(($g+$ng)/2),floor(($b+$nb)/2)); + } + imagesetpixel($newgdh,$sxt,$yt,$colidx); + } + + $set[$xt] = true; + } + + return $newgdh; + } + + // -------------------------------------------------------------------- + // Skew image for the apperance of a 3D effect + // This transforms an image into a 3D-skewed version + // of the image. The transformation is specified by giving the height + // of the artificial horizon and specifying a "skew" factor which + // is the distance on the horizon line between the point of + // convergence and perspective line. + // + // The function returns the GD handle of the transformed image + // leaving the original image untouched. + // + // Parameters: + // * $aGdImg, GD handle to the image to be transformed + // * $aHorizon, Distance to the horizon + // * $aSkewDist, Distance from the horizon point of convergence + // on the horizon line to the perspective points. A larger + // value will fore-shorten the image more + // * $aDir, parameter specifies type of convergence. This of this + // as the walls in a room you are looking at. This specifies if the + // image should be applied on the left,right,top or bottom walls. + // * $aMinSize, true=make the new image just as big as needed, + // false = keep the image the same size as the original image + // * $aFillColor, Background fill color in the image + // * $aHiQuality, true=performa some interpolation that improves + // the image quality but at the expense of performace. Enabling + // high quality will have a dramatic effect on the time it takes + // to transform an image. + // * $aBorder, if set to anything besides false this will draw a + // a border of the speciied color around the image + // -------------------------------------------------------------------- + function Skew3D($aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { + return $this->_Skew3D($this->gdImg,$aHorizon,$aSkewDist,$aDir,$aHiQuality, + $aMinSize,$aFillColor,$aBorder); + } + + function _Skew3D($aGdImg,$aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { + if( $aDir == SKEW3D_DOWN || $aDir == SKEW3D_UP ) + return $this->_TransVert3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); + else + return $this->_TransHor3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); + + } + +} + + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_led.php b/ext/jpgraph-3.0.7/src/jpgraph_led.php index 45cda1b..c2e9e8c 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_led.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_led.php @@ -1,311 +1,311 @@ - array('red','darkred:0.9','red:0.3'),// 0 - LEDC_GREEN => array('green','darkgreen','green:0.3'),// 1 - LEDC_BLUE => array('lightblue:0.9','darkblue:0.85','darkblue:0.7'),// 2 - LEDC_YELLOW => array('yellow','yellow:0.4','yellow:0.3'),// 3 - LEDC_GRAY => array('gray:1.4','darkgray:0.85','darkgray:0.7'), - LEDC_CHOCOLATE => array('chocolate','chocolate:0.7','chocolate:0.5'), - LEDC_PERU => array('peru:0.95','peru:0.6','peru:0.5'), - LEDC_GOLDENROD => array('goldenrod','goldenrod:0.6','goldenrod:0.5'), - LEDC_KHAKI => array('khaki:0.7','khaki:0.4','khaki:0.3'), - LEDC_OLIVE => array('#808000','#808000:0.7','#808000:0.6'), - LEDC_LIMEGREEN => array('limegreen:0.9','limegreen:0.5','limegreen:0.4'), - LEDC_FORESTGREEN => array('forestgreen','forestgreen:0.7','forestgreen:0.5'), - LEDC_TEAL => array('teal','teal:0.7','teal:0.5'), - LEDC_STEELBLUE => array('steelblue','steelblue:0.65','steelblue:0.5'), - LEDC_NAVY => array('navy:1.3','navy:0.95','navy:0.8'),//14 - LEDC_INVERTGRAY => array('darkgray','lightgray:1.5','white')//15 - ), - - /* Each line of the character is encoded as a 4 bit value - 0 ____ - 1 ___x - 2 __x_ - 3 __xx - 4 _x__ - 5 _x_x - 6 _xx_ - 7 _xxx - 8 x___ - 9 x__x - 10 x_x_ - 11 x_xx - 12 xx__ - 13 xx_x - 14 xxx_ - 15 xxxx - */ - - $iLEDSpec = array( - 0 => array(6,9,11,15,13,9,6), - 1 => array(2,6,10,2,2,2,2), - 2 => array(6,9,1,2,4,8,15), - 3 => array(6,9,1,6,1,9,6), - 4 => array(1,3,5,9,15,1,1), - 5 => array(15,8,8,14,1,9,6), - 6 => array(6,8,8,14,9,9,6), - 7 => array(15,1,1,2,4,4,4), - 8 => array(6,9,9,6,9,9,6), - 9 => array(6,9,9,7,1,1,6), - '!' => array(4,4,4,4,4,0,4), - '?' => array(6,9,1,2,2,0,2), - '#' => array(0,9,15,9,15,9,0), - '@' => array(6,9,11,11,10,9,6), - '-' => array(0,0,0,15,0,0,0), - '_' => array(0,0,0,0,0,0,15), - '=' => array(0,0,15,0,15,0,0), - '+' => array(0,0,4,14,4,0,0), - '|' => array(4,4,4,4,4,4,4), //vertical line, used for simulate rus 'Ы' - ',' => array(0,0,0,0,0,12,4), - '.' => array(0,0,0,0,0,12,12), - ':' => array(12,12,0,0,0,12,12), - ';' => array(12,12,0,0,0,12,4), - '[' => array(3,2,2,2,2,2,3), - ']' => array(12,4,4,4,4,4,12), - '(' => array(1,2,2,2,2,2,1), - ')' => array(8,4,4,4,4,4,8), - '{' => array(3,2,2,6,2,2,3), - '}' => array(12,4,4,6,4,4,12), - '<' => array(1,2,4,8,4,2,1), - '>' => array(8,4,2,1,2,4,8), - '*' => array(9,6,15,6,9,0,0), - '"' => array(10,10,0,0,0,0,0), - '\'' => array(4,4,0,0,0,0,0), - '`' => array(4,2,0,0,0,0,0), - '~' => array(13,11,0,0,0,0,0), - '^' => array(4,10,0,0,0,0,0), - '\\' => array(8,8,4,6,2,1,1), - '/' => array(1,1,2,6,4,8,8), - '%' => array(1,9,2,6,4,9,8), - '&' => array(0,4,10,4,11,10,5), - '$' => array(2,7,8,6,1,14,4), - ' ' => array(0,0,0,0,0,0,0), - '•' => array(0,0,6,6,0,0,0), //149 - '°' => array(14,10,14,0,0,0,0), //176 - '†' => array(4,4,14,4,4,4,4), //134 - '‡' => array(4,4,14,4,14,4,4), //135 - '±' => array(0,4,14,4,0,14,0), //177 - '‰' => array(0,4,2,15,2,4,0), //137 show right arrow - '™' => array(0,2,4,15,4,2,0), //156 show left arrow - 'Ў' => array(0,0,8,8,0,0,0), //159 show small hi-stick - that need for simulate rus 'Ѐ' - "\t" => array(8,8,8,0,0,0,0), //show hi-stick - that need for simulate rus 'У' - "\r" => array(8,8,8,8,8,8,8), //vertical line - that need for simulate 'M', 'W' and rus 'М','К' ,'Щ' - "\n" => array(15,15,15,15,15,15,15), //fill up - that need for simulate rus 'Ж' - "Ґ" => array(10,5,10,5,10,5,10), //chess - "µ" => array(15,0,15,0,15,0,15), //4 horizontal lines - // latin - 'A' => array(6,9,9,15,9,9,9), - 'B' => array(14,9,9,14,9,9,14), - 'C' => array(6,9,8,8,8,9,6), - 'D' => array(14,9,9,9,9,9,14), - 'E' => array(15,8,8,14,8,8,15), - 'F' => array(15,8,8,14,8,8,8), - 'G' => array(6,9,8,8,11,9,6), - 'H' => array(9,9,9,15,9,9,9), - 'I' => array(14,4,4,4,4,4,14), - 'J' => array(15,1,1,1,1,9,6), - 'K' => array(8,9,10,12,12,10,9), - 'L' => array(8,8,8,8,8,8,15), - 'M' => array(8,13,10,8,8,8,8),// need to add \r - 'N' => array(9,9,13,11,9,9,9), - 'O' => array(6,9,9,9,9,9,6), - 'P' => array(14,9,9,14,8,8,8), - 'Q' => array(6,9,9,9,13,11,6), - 'R' => array(14,9,9,14,12,10,9), - 'S' => array(6,9,8,6,1,9,6), - 'T' => array(14,4,4,4,4,4,4), - 'U' => array(9,9,9,9,9,9,6), - 'V' => array(0,0,0,10,10,10,4), - 'W' => array(8,8,8,8,10,13,8),// need to add \r - 'X' => array(9,9,6,6,6,9,9), - 'Y' => array(10,10,10,10,4,4,4), - 'Z' => array(15,1,2,6,4,8,15), - // russian utf-8 - 'А' => array(6,9,9,15,9,9,9), - 'Б' => array(14,8,8,14,9,9,14), - 'В' => array(14,9,9,14,9,9,14), - 'Г' => array(15,8,8,8,8,8,8), - 'Д' => array(14,9,9,9,9,9,14), - 'Е' => array(15,8,8,14,8,8,15), - 'Ё' => array(6,15,8,14,8,8,15), - //Ж is combine: >\n< - 'З' => array(6,9,1,2,1,9,6), - 'И' => array(9,9,9,11,13,9,9), - 'Й' => array(13,9,9,11,13,9,9), - 'К' => array(9,10,12,10,9,9,9), - 'Л' => array(7,9,9,9,9,9,9), - 'М' => array(8,13,10,8,8,8,8),// need to add \r - 'Н' => array(9,9,9,15,9,9,9), - 'О' => array(6,9,9,9,9,9,6), - 'П' => array(15,9,9,9,9,9,9), - 'Р' => array(14,9,9,14,8,8,8), - 'С' => array(6,9,8,8,8,9,6), - 'Т' => array(14,4,4,4,4,4,4), - 'У' => array(9,9,9,7,1,9,6), - 'Ѐ' => array(2,7,10,10,7,2,2),// need to add Ў - 'Ð¥' => array(9,9,6,6,6,9,9), - 'Њ' => array(10,10,10,10,10,15,1), - 'Ч' => array(9,9,9,7,1,1,1), - 'К' => array(10,10,10,10,10,10,15),// \r - 'Щ' => array(10,10,10,10,10,15,0),// need to add \r - 'Ъ' => array(12,4,4,6,5,5,6), - 'Ы' => array(8,8,8,14,9,9,14),// need to add | - 'Ь' => array(8,8,8,14,9,9,14), - 'Э' => array(6,9,1,7,1,9,6), - 'Ю' => array(2,2,2,3,2,2,2),// need to add O - 'Я' => array(7,9,9,7,3,5,9) - ), - - $iSuperSampling = 3, $iMarg = 1, $iRad = 4; - - function __construct($aRadius = 2, $aMargin= 0.6) { - $this->iRad = $aRadius; - $this->iMarg = $aMargin; - } - - function SetSupersampling($aSuperSampling = 2) { - $this->iSuperSampling = $aSuperSampling; - } - - function _GetLED($aLedIdx, $aColor = 0) { - $width= $this->iLED_X*$this->iRad*2 + ($this->iLED_X+1)*$this->iMarg + $this->iRad ; - $height= $this->iLED_Y*$this->iRad*2 + ($this->iLED_Y)*$this->iMarg + $this->iRad * 2; - - // Adjust radious for supersampling - $rad = $this->iRad * $this->iSuperSampling; - - // Margin in between "Led" dots - $marg = $this->iMarg * $this->iSuperSampling; - - $swidth = $width*$this->iSuperSampling; - $sheight = $height*$this->iSuperSampling; - - $simg = new RotImage($swidth, $sheight, 0, DEFAULT_GFORMAT, false); - $simg->SetColor($this->iColorSchema[$aColor][2]); - $simg->FilledRectangle(0, 0, $swidth-1, $sheight-1); - - if( array_key_exists($aLedIdx, $this->iLEDSpec) ) { - $d = $this->iLEDSpec[$aLedIdx]; - } - else { - $d = array(0,0,0,0,0,0,0); - } - - for($r = 0; $r < 7; ++$r) { - $dr = $d[$r]; - for($c = 0; $c < 4; ++$c) { - if( ($dr & pow(2,3-$c)) !== 0 ) { - $color = $this->iColorSchema[$aColor][0]; - } - else { - $color = $this->iColorSchema[$aColor][1]; - } - - $x = 2*$rad*$c+$rad + ($c+1)*$marg + $rad ; - $y = 2*$rad*$r+$rad + ($r+1)*$marg + $rad ; - - $simg->SetColor($color); - $simg->FilledCircle($x,$y,$rad); - } - } - - $img = new Image($width, $height, DEFAULT_GFORMAT, false); - $img->Copy($simg->img, 0, 0, 0, 0, $width, $height, $swidth, $sheight); - $simg->Destroy(); - unset($simg); - return $img; - } - - - function Stroke($aValStr, $aColor = 0, $aFileName = '') { - $this->StrokeNumber($aValStr, $aColor, $aFileName); - } - - - function StrokeNumber($aValStr, $aColor = 0, $aFileName = '') { - if( $aColor < 0 || $aColor >= sizeof($this->iColorSchema) ) { - $aColor = 0; - } - - if(($n = mb_strlen($aValStr,'utf8')) == 0) { - $aValStr = ' '; - $n = 1; - } - - for($i = 0; $i < $n; ++$i) { - $d = mb_substr($aValStr, $i, 1, 'utf8'); - if( ctype_digit($d) ) { - $d = (int)$d; - } - else { - $d = strtoupper($d); - } - $digit_img[$i] = $this->_GetLED($d, $aColor); - } - - $w = imagesx($digit_img[0]->img); - $h = imagesy($digit_img[0]->img); - - $number_img = new Image($w*$n, $h, DEFAULT_GFORMAT, false); - - for($i = 0; $i < $n; ++$i) { - $number_img->Copy($digit_img[$i]->img, $i*$w, 0, 0, 0, $w, $h, $w, $h); - } - - if( $aFileName != '' ) { - $number_img->Stream($aFileName); - } else { - $number_img->Headers(); - $number_img->Stream(); - } - } -} -?> + array('red','darkred:0.9','red:0.3'),// 0 + LEDC_GREEN => array('green','darkgreen','green:0.3'),// 1 + LEDC_BLUE => array('lightblue:0.9','darkblue:0.85','darkblue:0.7'),// 2 + LEDC_YELLOW => array('yellow','yellow:0.4','yellow:0.3'),// 3 + LEDC_GRAY => array('gray:1.4','darkgray:0.85','darkgray:0.7'), + LEDC_CHOCOLATE => array('chocolate','chocolate:0.7','chocolate:0.5'), + LEDC_PERU => array('peru:0.95','peru:0.6','peru:0.5'), + LEDC_GOLDENROD => array('goldenrod','goldenrod:0.6','goldenrod:0.5'), + LEDC_KHAKI => array('khaki:0.7','khaki:0.4','khaki:0.3'), + LEDC_OLIVE => array('#808000','#808000:0.7','#808000:0.6'), + LEDC_LIMEGREEN => array('limegreen:0.9','limegreen:0.5','limegreen:0.4'), + LEDC_FORESTGREEN => array('forestgreen','forestgreen:0.7','forestgreen:0.5'), + LEDC_TEAL => array('teal','teal:0.7','teal:0.5'), + LEDC_STEELBLUE => array('steelblue','steelblue:0.65','steelblue:0.5'), + LEDC_NAVY => array('navy:1.3','navy:0.95','navy:0.8'),//14 + LEDC_INVERTGRAY => array('darkgray','lightgray:1.5','white')//15 + ), + + /* Each line of the character is encoded as a 4 bit value + 0 ____ + 1 ___x + 2 __x_ + 3 __xx + 4 _x__ + 5 _x_x + 6 _xx_ + 7 _xxx + 8 x___ + 9 x__x + 10 x_x_ + 11 x_xx + 12 xx__ + 13 xx_x + 14 xxx_ + 15 xxxx + */ + + $iLEDSpec = array( + 0 => array(6,9,11,15,13,9,6), + 1 => array(2,6,10,2,2,2,2), + 2 => array(6,9,1,2,4,8,15), + 3 => array(6,9,1,6,1,9,6), + 4 => array(1,3,5,9,15,1,1), + 5 => array(15,8,8,14,1,9,6), + 6 => array(6,8,8,14,9,9,6), + 7 => array(15,1,1,2,4,4,4), + 8 => array(6,9,9,6,9,9,6), + 9 => array(6,9,9,7,1,1,6), + '!' => array(4,4,4,4,4,0,4), + '?' => array(6,9,1,2,2,0,2), + '#' => array(0,9,15,9,15,9,0), + '@' => array(6,9,11,11,10,9,6), + '-' => array(0,0,0,15,0,0,0), + '_' => array(0,0,0,0,0,0,15), + '=' => array(0,0,15,0,15,0,0), + '+' => array(0,0,4,14,4,0,0), + '|' => array(4,4,4,4,4,4,4), //vertical line, used for simulate rus 'Ы' + ',' => array(0,0,0,0,0,12,4), + '.' => array(0,0,0,0,0,12,12), + ':' => array(12,12,0,0,0,12,12), + ';' => array(12,12,0,0,0,12,4), + '[' => array(3,2,2,2,2,2,3), + ']' => array(12,4,4,4,4,4,12), + '(' => array(1,2,2,2,2,2,1), + ')' => array(8,4,4,4,4,4,8), + '{' => array(3,2,2,6,2,2,3), + '}' => array(12,4,4,6,4,4,12), + '<' => array(1,2,4,8,4,2,1), + '>' => array(8,4,2,1,2,4,8), + '*' => array(9,6,15,6,9,0,0), + '"' => array(10,10,0,0,0,0,0), + '\'' => array(4,4,0,0,0,0,0), + '`' => array(4,2,0,0,0,0,0), + '~' => array(13,11,0,0,0,0,0), + '^' => array(4,10,0,0,0,0,0), + '\\' => array(8,8,4,6,2,1,1), + '/' => array(1,1,2,6,4,8,8), + '%' => array(1,9,2,6,4,9,8), + '&' => array(0,4,10,4,11,10,5), + '$' => array(2,7,8,6,1,14,4), + ' ' => array(0,0,0,0,0,0,0), + '•' => array(0,0,6,6,0,0,0), //149 + '°' => array(14,10,14,0,0,0,0), //176 + '†' => array(4,4,14,4,4,4,4), //134 + '‡' => array(4,4,14,4,14,4,4), //135 + '±' => array(0,4,14,4,0,14,0), //177 + '‰' => array(0,4,2,15,2,4,0), //137 show right arrow + '™' => array(0,2,4,15,4,2,0), //156 show left arrow + 'Ў' => array(0,0,8,8,0,0,0), //159 show small hi-stick - that need for simulate rus 'Ѐ' + "\t" => array(8,8,8,0,0,0,0), //show hi-stick - that need for simulate rus 'У' + "\r" => array(8,8,8,8,8,8,8), //vertical line - that need for simulate 'M', 'W' and rus 'М','К' ,'Щ' + "\n" => array(15,15,15,15,15,15,15), //fill up - that need for simulate rus 'Ж' + "Ґ" => array(10,5,10,5,10,5,10), //chess + "µ" => array(15,0,15,0,15,0,15), //4 horizontal lines + // latin + 'A' => array(6,9,9,15,9,9,9), + 'B' => array(14,9,9,14,9,9,14), + 'C' => array(6,9,8,8,8,9,6), + 'D' => array(14,9,9,9,9,9,14), + 'E' => array(15,8,8,14,8,8,15), + 'F' => array(15,8,8,14,8,8,8), + 'G' => array(6,9,8,8,11,9,6), + 'H' => array(9,9,9,15,9,9,9), + 'I' => array(14,4,4,4,4,4,14), + 'J' => array(15,1,1,1,1,9,6), + 'K' => array(8,9,10,12,12,10,9), + 'L' => array(8,8,8,8,8,8,15), + 'M' => array(8,13,10,8,8,8,8),// need to add \r + 'N' => array(9,9,13,11,9,9,9), + 'O' => array(6,9,9,9,9,9,6), + 'P' => array(14,9,9,14,8,8,8), + 'Q' => array(6,9,9,9,13,11,6), + 'R' => array(14,9,9,14,12,10,9), + 'S' => array(6,9,8,6,1,9,6), + 'T' => array(14,4,4,4,4,4,4), + 'U' => array(9,9,9,9,9,9,6), + 'V' => array(0,0,0,10,10,10,4), + 'W' => array(8,8,8,8,10,13,8),// need to add \r + 'X' => array(9,9,6,6,6,9,9), + 'Y' => array(10,10,10,10,4,4,4), + 'Z' => array(15,1,2,6,4,8,15), + // russian utf-8 + 'А' => array(6,9,9,15,9,9,9), + 'Б' => array(14,8,8,14,9,9,14), + 'В' => array(14,9,9,14,9,9,14), + 'Г' => array(15,8,8,8,8,8,8), + 'Д' => array(14,9,9,9,9,9,14), + 'Е' => array(15,8,8,14,8,8,15), + 'Ё' => array(6,15,8,14,8,8,15), + //Ж is combine: >\n< + 'З' => array(6,9,1,2,1,9,6), + 'И' => array(9,9,9,11,13,9,9), + 'Й' => array(13,9,9,11,13,9,9), + 'К' => array(9,10,12,10,9,9,9), + 'Л' => array(7,9,9,9,9,9,9), + 'М' => array(8,13,10,8,8,8,8),// need to add \r + 'Н' => array(9,9,9,15,9,9,9), + 'О' => array(6,9,9,9,9,9,6), + 'П' => array(15,9,9,9,9,9,9), + 'Р' => array(14,9,9,14,8,8,8), + 'С' => array(6,9,8,8,8,9,6), + 'Т' => array(14,4,4,4,4,4,4), + 'У' => array(9,9,9,7,1,9,6), + 'Ѐ' => array(2,7,10,10,7,2,2),// need to add Ў + 'Ð¥' => array(9,9,6,6,6,9,9), + 'Њ' => array(10,10,10,10,10,15,1), + 'Ч' => array(9,9,9,7,1,1,1), + 'К' => array(10,10,10,10,10,10,15),// \r + 'Щ' => array(10,10,10,10,10,15,0),// need to add \r + 'Ъ' => array(12,4,4,6,5,5,6), + 'Ы' => array(8,8,8,14,9,9,14),// need to add | + 'Ь' => array(8,8,8,14,9,9,14), + 'Э' => array(6,9,1,7,1,9,6), + 'Ю' => array(2,2,2,3,2,2,2),// need to add O + 'Я' => array(7,9,9,7,3,5,9) + ), + + $iSuperSampling = 3, $iMarg = 1, $iRad = 4; + + function __construct($aRadius = 2, $aMargin= 0.6) { + $this->iRad = $aRadius; + $this->iMarg = $aMargin; + } + + function SetSupersampling($aSuperSampling = 2) { + $this->iSuperSampling = $aSuperSampling; + } + + function _GetLED($aLedIdx, $aColor = 0) { + $width= $this->iLED_X*$this->iRad*2 + ($this->iLED_X+1)*$this->iMarg + $this->iRad ; + $height= $this->iLED_Y*$this->iRad*2 + ($this->iLED_Y)*$this->iMarg + $this->iRad * 2; + + // Adjust radious for supersampling + $rad = $this->iRad * $this->iSuperSampling; + + // Margin in between "Led" dots + $marg = $this->iMarg * $this->iSuperSampling; + + $swidth = $width*$this->iSuperSampling; + $sheight = $height*$this->iSuperSampling; + + $simg = new RotImage($swidth, $sheight, 0, DEFAULT_GFORMAT, false); + $simg->SetColor($this->iColorSchema[$aColor][2]); + $simg->FilledRectangle(0, 0, $swidth-1, $sheight-1); + + if( array_key_exists($aLedIdx, $this->iLEDSpec) ) { + $d = $this->iLEDSpec[$aLedIdx]; + } + else { + $d = array(0,0,0,0,0,0,0); + } + + for($r = 0; $r < 7; ++$r) { + $dr = $d[$r]; + for($c = 0; $c < 4; ++$c) { + if( ($dr & pow(2,3-$c)) !== 0 ) { + $color = $this->iColorSchema[$aColor][0]; + } + else { + $color = $this->iColorSchema[$aColor][1]; + } + + $x = 2*$rad*$c+$rad + ($c+1)*$marg + $rad ; + $y = 2*$rad*$r+$rad + ($r+1)*$marg + $rad ; + + $simg->SetColor($color); + $simg->FilledCircle($x,$y,$rad); + } + } + + $img = new Image($width, $height, DEFAULT_GFORMAT, false); + $img->Copy($simg->img, 0, 0, 0, 0, $width, $height, $swidth, $sheight); + $simg->Destroy(); + unset($simg); + return $img; + } + + + function Stroke($aValStr, $aColor = 0, $aFileName = '') { + $this->StrokeNumber($aValStr, $aColor, $aFileName); + } + + + function StrokeNumber($aValStr, $aColor = 0, $aFileName = '') { + if( $aColor < 0 || $aColor >= sizeof($this->iColorSchema) ) { + $aColor = 0; + } + + if(($n = mb_strlen($aValStr,'utf8')) == 0) { + $aValStr = ' '; + $n = 1; + } + + for($i = 0; $i < $n; ++$i) { + $d = mb_substr($aValStr, $i, 1, 'utf8'); + if( ctype_digit($d) ) { + $d = (int)$d; + } + else { + $d = strtoupper($d); + } + $digit_img[$i] = $this->_GetLED($d, $aColor); + } + + $w = imagesx($digit_img[0]->img); + $h = imagesy($digit_img[0]->img); + + $number_img = new Image($w*$n, $h, DEFAULT_GFORMAT, false); + + for($i = 0; $i < $n; ++$i) { + $number_img->Copy($digit_img[$i]->img, $i*$w, 0, 0, 0, $w, $h, $w, $h); + } + + if( $aFileName != '' ) { + $number_img->Stream($aFileName); + } else { + $number_img->Headers(); + $number_img->Stream(); + } + } +} +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_legend.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_legend.inc.php index 58fd432..8905ecf 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_legend.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_legend.inc.php @@ -1,484 +1,484 @@ -hide=$aHide; - } - - function SetHColMargin($aXMarg) { - $this->xmargin = $aXMarg; - } - - function SetVColMargin($aSpacing) { - $this->ylinespacing = $aSpacing ; - } - - function SetLeftMargin($aXMarg) { - $this->xlmargin = $aXMarg; - } - - // Synonym - function SetLineSpacing($aSpacing) { - $this->ylinespacing = $aSpacing ; - } - - function SetShadow($aShow='gray',$aWidth=4) { - if( is_string($aShow) ) { - $this->shadow_color = $aShow; - $this->shadow=true; - } - else { - $this->shadow = $aShow; - } - $this->shadow_width = $aWidth; - } - - function SetMarkAbsSize($aSize) { - $this->mark_abs_vsize = $aSize ; - $this->mark_abs_hsize = $aSize ; - } - - function SetMarkAbsVSize($aSize) { - $this->mark_abs_vsize = $aSize ; - } - - function SetMarkAbsHSize($aSize) { - $this->mark_abs_hsize = $aSize ; - } - - function SetLineWeight($aWeight) { - $this->weight = $aWeight; - } - - function SetFrameWeight($aWeight) { - $this->frameweight = $aWeight; - } - - function SetLayout($aDirection=LEGEND_VERT) { - $this->layout_n = $aDirection==LEGEND_VERT ? 1 : 99 ; - } - - function SetColumns($aCols) { - $this->layout_n = $aCols ; - } - - function SetReverse($f=true) { - $this->reverse = $f ; - } - - // Set color on frame around box - function SetColor($aFontColor,$aColor='black') { - $this->font_color=$aFontColor; - $this->color=$aColor; - } - - function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { - $this->font_family = $aFamily; - $this->font_style = $aStyle; - $this->font_size = $aSize; - } - - function SetPos($aX,$aY,$aHAlign='right',$aVAlign='top') { - $this->Pos($aX,$aY,$aHAlign,$aVAlign); - } - - function SetAbsPos($aX,$aY,$aHAlign='right',$aVAlign='top') { - $this->xabspos=$aX; - $this->yabspos=$aY; - $this->halign=$aHAlign; - $this->valign=$aVAlign; - } - - function Pos($aX,$aY,$aHAlign='right',$aVAlign='top') { - if( !($aX<1 && $aY<1) ) { - JpGraphError::RaiseL(25120);//(" Position for legend must be given as percentage in range 0-1"); - } - $this->xpos=$aX; - $this->ypos=$aY; - $this->halign=$aHAlign; - $this->valign=$aVAlign; - } - - function SetFillColor($aColor) { - $this->fill_color=$aColor; - } - - function Clear() { - $this->txtcol = array(); - } - - function Add($aTxt,$aColor,$aPlotmark='',$aLinestyle=0,$csimtarget='',$csimalt='',$csimwintarget='') { - $this->txtcol[]=array($aTxt,$aColor,$aPlotmark,$aLinestyle,$csimtarget,$csimalt,$csimwintarget); - } - - function GetCSIMAreas() { - return $this->csimareas; - } - - function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2) { - $this->bkg_gradtype=$aGradType; - $this->bkg_gradfrom = $aFrom; - $this->bkg_gradto = $aTo; - } - - function Stroke($aImg) { - // Constant - $fillBoxFrameWeight=1; - - if( $this->hide ) return; - - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - - if( $this->reverse ) { - $this->txtcol = array_reverse($this->txtcol); - } - - $n=count($this->txtcol); - if( $n == 0 ) return; - - // Find out the max width and height of each column to be able - // to size the legend box. - $numcolumns = ($n > $this->layout_n ? $this->layout_n : $n); - for( $i=0; $i < $numcolumns; ++$i ) { - $colwidth[$i] = $aImg->GetTextWidth($this->txtcol[$i][0]) + - 2*$this->xmargin + 2*$this->mark_abs_hsize; - $colheight[$i] = 0; - - } - - // Find our maximum height in each row - $rows = 0 ; $rowheight[0] = 0; - for( $i=0; $i < $n; ++$i ) { - $h = max($this->mark_abs_vsize,$aImg->GetTextHeight($this->txtcol[$i][0]))+$this->ylinespacing; - - // Makes sure we always have a minimum of 1/4 (1/2 on each side) of the mark as space - // between two vertical legend entries - //$h = round(max($h,$this->mark_abs_vsize+$this->ymargin)); - //echo "Textheight #$i: tetxheight=".$aImg->GetTextHeight($this->txtcol[$i][0]).', '; - //echo "h=$h ({$this->mark_abs_vsize},{$this->ymargin})
      "; - if( $i % $numcolumns == 0 ) { - $rows++; - $rowheight[$rows-1] = 0; - } - $rowheight[$rows-1] = max($rowheight[$rows-1],$h); - } - - $abs_height = 0; - for( $i=0; $i < $rows; ++$i ) { - $abs_height += $rowheight[$i] ; - } - - // Make sure that the height is at least as high as mark size + ymargin - $abs_height = max($abs_height,$this->mark_abs_vsize); - $abs_height += $this->ybottom_margin; - - // Find out the maximum width in each column - for( $i=$numcolumns; $i < $n; ++$i ) { - $colwidth[$i % $numcolumns] = max( - $aImg->GetTextWidth($this->txtcol[$i][0])+2*$this->xmargin+2*$this->mark_abs_hsize, - $colwidth[$i % $numcolumns]); - } - - // Get the total width - $mtw = 0; - for( $i=0; $i < $numcolumns; ++$i ) { - $mtw += $colwidth[$i] ; - } - - // remove the last rows interpace margin (since there is no next row) - $abs_height -= $this->ylinespacing; - - - // Find out maximum width we need for legend box - $abs_width = $mtw+$this->xlmargin+($numcolumns-1)*$this->mark_abs_hsize; - - if( $this->xabspos === -1 && $this->yabspos === -1 ) { - $this->xabspos = $this->xpos*$aImg->width ; - $this->yabspos = $this->ypos*$aImg->height ; - } - - // Positioning of the legend box - if( $this->halign == 'left' ) { - $xp = $this->xabspos; - } - elseif( $this->halign == 'center' ) { - $xp = $this->xabspos - $abs_width/2; - } - else { - $xp = $aImg->width - $this->xabspos - $abs_width; - } - - $yp=$this->yabspos; - if( $this->valign == 'center' ) { - $yp-=$abs_height/2; - } - elseif( $this->valign == 'bottom' ) { - $yp-=$abs_height; - } - - // Stroke legend box - $aImg->SetColor($this->color); - $aImg->SetLineWeight($this->frameweight); - $aImg->SetLineStyle('solid'); - - if( $this->shadow ) { - $aImg->ShadowRectangle($xp,$yp, - $xp+$abs_width+$this->shadow_width+2, - $yp+$abs_height+$this->shadow_width+2, - $this->fill_color,$this->shadow_width+2,$this->shadow_color); - } - else { - $aImg->SetColor($this->fill_color); - $aImg->FilledRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); - $aImg->SetColor($this->color); - $aImg->Rectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); - } - - if( $this->bkg_gradtype >= 0 ) { - $grad = new Gradient($aImg); - $grad->FilledRectangle($xp+1, $yp+1, - $xp+$abs_width-3, $yp+$abs_height-3, - $this->bkg_gradfrom, $this->bkg_gradto, - $this->bkg_gradtype); - } - - // x1,y1 is the position for the legend marker + text - // The vertical position is the baseline position for the text - // and every marker is adjusted acording to that. - - // For multiline texts this get more complicated. - - $x1 = $xp + $this->xlmargin; - $y1 = $yp + $rowheight[0] - $this->ylinespacing + 2 ; // The ymargin is included in rowheight - - // Now, y1 is the bottom vertical position of the first legend, i.e if - // the legend has multiple lines it is the bottom line. - - $grad = new Gradient($aImg); - $patternFactory = null; - - // Now stroke each legend in turn - // Each plot has added the following information to the legend - // p[0] = Legend text - // p[1] = Color, - // p[2] = For markers a reference to the PlotMark object - // p[3] = For lines the line style, for gradient the negative gradient style - // p[4] = CSIM target - // p[5] = CSIM Alt text - $i = 1 ; $row = 0; - foreach($this->txtcol as $p) { - - // STROKE DEBUG BOX - if( _JPG_DEBUG ) { - $aImg->SetLineWeight(1); - $aImg->SetColor('red'); - $aImg->SetLineStyle('solid'); - $aImg->Rectangle($x1,$y1,$xp+$abs_width-1,$y1-$rowheight[$row]); - } - - $aImg->SetLineWeight($this->weight); - $x1 = round($x1)+1; // We add one to not collide with the border - $y1=round($y1); - - // This is the center offset up from the baseline which is - // considered the "center" of the marks. This gets slightly complicated since - // we need to consider if the text is a multiline paragraph or if it is only - // a single line. The reason is that for single line the y1 corresponds to the baseline - // and that is fine. However for a multiline paragraph there is no single baseline - // and in that case the y1 corresponds to the lowest y for the bounding box. In that - // case we center the mark in the middle of the paragraph - if( !preg_match('/\n/',$p[0]) ) { - // Single line - $marky = ceil($y1-$this->mark_abs_vsize/2)-1; - } else { - // Paragraph - $marky = $y1 - $aImg->GetTextHeight($p[0])/2; - - // echo "y1=$y1, p[o]={$p[0]}, marky=$marky
      "; - } - - //echo "
      Mark #$i: marky=$marky
      "; - - $x1 += $this->mark_abs_hsize; - - if ( !empty($p[2]) && $p[2]->GetType() > -1 ) { - - - // Make a plot mark legend. This is constructed with a mark which - // is run through with a line - - // First construct a bit of the line that looks exactly like the - // line in the plot - $aImg->SetColor($p[1]); - if( is_string($p[3]) || $p[3]>0 ) { - $aImg->SetLineStyle($p[3]); - $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky,$x1+$this->mark_abs_hsize,$marky); - } - - // Stroke a mark with the standard size - // (As long as it is not an image mark ) - if( $p[2]->GetType() != MARK_IMG ) { - - // Clear any user callbacks since we ont want them called for - // the legend marks - $p[2]->iFormatCallback = ''; - $p[2]->iFormatCallback2 = ''; - - // Since size for circles is specified as the radius - // this means that we must half the size to make the total - // width behave as the other marks - if( $p[2]->GetType() == MARK_FILLEDCIRCLE || $p[2]->GetType() == MARK_CIRCLE ) { - $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)/2); - $p[2]->Stroke($aImg,$x1,$marky); - } - else { - $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)); - $p[2]->Stroke($aImg,$x1,$marky); - } - } - } - elseif ( !empty($p[2]) && (is_string($p[3]) || $p[3]>0 ) ) { - // Draw a styled line - $aImg->SetColor($p[1]); - $aImg->SetLineStyle($p[3]); - $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky,$x1+$this->mark_abs_hsize,$marky); - $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky+1,$x1+$this->mark_abs_hsize,$marky+1); - } - else { - // Draw a colored box - $color = $p[1] ; - - // We make boxes slightly larger to better show - $boxsize = max($this->mark_abs_vsize,$this->mark_abs_hsize) + 2 ; - - $ym = $marky-ceil($boxsize/2) ; // Marker y-coordinate - - // We either need to plot a gradient or a - // pattern. To differentiate we use a kludge. - // Patterns have a p[3] value of < -100 - if( $p[3] < -100 ) { - // p[1][0] == iPattern, p[1][1] == iPatternColor, p[1][2] == iPatternDensity - if( $patternFactory == null ) { - $patternFactory = new RectPatternFactory(); - } - $prect = $patternFactory->Create($p[1][0],$p[1][1],1); - $prect->SetBackground($p[1][3]); - $prect->SetDensity($p[1][2]+1); - $prect->SetPos(new Rectangle($x1,$ym,$boxsize,$boxsize)); - $prect->Stroke($aImg); - $prect=null; - } - else { - if( is_array($color) && count($color)==2 ) { - // The client want a gradient color - $grad->FilledRectangle($x1-$boxsize/2,$ym, - $x1+$boxsize/2,$ym+$boxsize, - $color[0],$color[1],-$p[3]); - } - else { - $aImg->SetColor($p[1]); - $aImg->FilledRectangle($x1-$boxsize/2,$ym, - $x1+$boxsize/2,$ym+$boxsize); - } - $aImg->SetColor($this->color); - $aImg->SetLineWeight($fillBoxFrameWeight); - $aImg->Rectangle($x1-$boxsize/2,$ym, - $x1+$boxsize/2,$ym+$boxsize); - } - } - $aImg->SetColor($this->font_color); - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $aImg->SetTextAlign('left','baseline'); - - $debug=false; - $aImg->StrokeText($x1+$this->mark_abs_hsize+$this->xmargin,$y1,$p[0], - 0,'left',$debug); - - // Add CSIM for Legend if defined - if( !empty($p[4]) ) { - - $xs = $x1 - $this->mark_abs_hsize ; - $ys = $y1 + 1 ; - $xe = $x1 + $aImg->GetTextWidth($p[0]) + $this->mark_abs_hsize + $this->xmargin ; - $ye = $y1-$rowheight[$row]+1; - $coords = "$xs,$ys,$xe,$y1,$xe,$ye,$xs,$ye"; - if( ! empty($p[4]) ) { - $this->csimareas .= "csimareas .= " target=\"".$p[6]."\""; - } - - if( !empty($p[5]) ) { - $tmp=sprintf($p[5],$p[0]); - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - } - - if( $i >= $this->layout_n ) { - $x1 = $xp+$this->xlmargin; - $row++; - if( !empty($rowheight[$row]) ) - $y1 += $rowheight[$row]; - $i = 1; - } - else { - $x1 += $colwidth[($i-1) % $numcolumns] ; - ++$i; - } - } - } -} // Class - -?> +hide=$aHide; + } + + function SetHColMargin($aXMarg) { + $this->xmargin = $aXMarg; + } + + function SetVColMargin($aSpacing) { + $this->ylinespacing = $aSpacing ; + } + + function SetLeftMargin($aXMarg) { + $this->xlmargin = $aXMarg; + } + + // Synonym + function SetLineSpacing($aSpacing) { + $this->ylinespacing = $aSpacing ; + } + + function SetShadow($aShow='gray',$aWidth=4) { + if( is_string($aShow) ) { + $this->shadow_color = $aShow; + $this->shadow=true; + } + else { + $this->shadow = $aShow; + } + $this->shadow_width = $aWidth; + } + + function SetMarkAbsSize($aSize) { + $this->mark_abs_vsize = $aSize ; + $this->mark_abs_hsize = $aSize ; + } + + function SetMarkAbsVSize($aSize) { + $this->mark_abs_vsize = $aSize ; + } + + function SetMarkAbsHSize($aSize) { + $this->mark_abs_hsize = $aSize ; + } + + function SetLineWeight($aWeight) { + $this->weight = $aWeight; + } + + function SetFrameWeight($aWeight) { + $this->frameweight = $aWeight; + } + + function SetLayout($aDirection=LEGEND_VERT) { + $this->layout_n = $aDirection==LEGEND_VERT ? 1 : 99 ; + } + + function SetColumns($aCols) { + $this->layout_n = $aCols ; + } + + function SetReverse($f=true) { + $this->reverse = $f ; + } + + // Set color on frame around box + function SetColor($aFontColor,$aColor='black') { + $this->font_color=$aFontColor; + $this->color=$aColor; + } + + function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { + $this->font_family = $aFamily; + $this->font_style = $aStyle; + $this->font_size = $aSize; + } + + function SetPos($aX,$aY,$aHAlign='right',$aVAlign='top') { + $this->Pos($aX,$aY,$aHAlign,$aVAlign); + } + + function SetAbsPos($aX,$aY,$aHAlign='right',$aVAlign='top') { + $this->xabspos=$aX; + $this->yabspos=$aY; + $this->halign=$aHAlign; + $this->valign=$aVAlign; + } + + function Pos($aX,$aY,$aHAlign='right',$aVAlign='top') { + if( !($aX<1 && $aY<1) ) { + JpGraphError::RaiseL(25120);//(" Position for legend must be given as percentage in range 0-1"); + } + $this->xpos=$aX; + $this->ypos=$aY; + $this->halign=$aHAlign; + $this->valign=$aVAlign; + } + + function SetFillColor($aColor) { + $this->fill_color=$aColor; + } + + function Clear() { + $this->txtcol = array(); + } + + function Add($aTxt,$aColor,$aPlotmark='',$aLinestyle=0,$csimtarget='',$csimalt='',$csimwintarget='') { + $this->txtcol[]=array($aTxt,$aColor,$aPlotmark,$aLinestyle,$csimtarget,$csimalt,$csimwintarget); + } + + function GetCSIMAreas() { + return $this->csimareas; + } + + function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2) { + $this->bkg_gradtype=$aGradType; + $this->bkg_gradfrom = $aFrom; + $this->bkg_gradto = $aTo; + } + + function Stroke($aImg) { + // Constant + $fillBoxFrameWeight=1; + + if( $this->hide ) return; + + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + + if( $this->reverse ) { + $this->txtcol = array_reverse($this->txtcol); + } + + $n=count($this->txtcol); + if( $n == 0 ) return; + + // Find out the max width and height of each column to be able + // to size the legend box. + $numcolumns = ($n > $this->layout_n ? $this->layout_n : $n); + for( $i=0; $i < $numcolumns; ++$i ) { + $colwidth[$i] = $aImg->GetTextWidth($this->txtcol[$i][0]) + + 2*$this->xmargin + 2*$this->mark_abs_hsize; + $colheight[$i] = 0; + + } + + // Find our maximum height in each row + $rows = 0 ; $rowheight[0] = 0; + for( $i=0; $i < $n; ++$i ) { + $h = max($this->mark_abs_vsize,$aImg->GetTextHeight($this->txtcol[$i][0]))+$this->ylinespacing; + + // Makes sure we always have a minimum of 1/4 (1/2 on each side) of the mark as space + // between two vertical legend entries + //$h = round(max($h,$this->mark_abs_vsize+$this->ymargin)); + //echo "Textheight #$i: tetxheight=".$aImg->GetTextHeight($this->txtcol[$i][0]).', '; + //echo "h=$h ({$this->mark_abs_vsize},{$this->ymargin})
      "; + if( $i % $numcolumns == 0 ) { + $rows++; + $rowheight[$rows-1] = 0; + } + $rowheight[$rows-1] = max($rowheight[$rows-1],$h); + } + + $abs_height = 0; + for( $i=0; $i < $rows; ++$i ) { + $abs_height += $rowheight[$i] ; + } + + // Make sure that the height is at least as high as mark size + ymargin + $abs_height = max($abs_height,$this->mark_abs_vsize); + $abs_height += $this->ybottom_margin; + + // Find out the maximum width in each column + for( $i=$numcolumns; $i < $n; ++$i ) { + $colwidth[$i % $numcolumns] = max( + $aImg->GetTextWidth($this->txtcol[$i][0])+2*$this->xmargin+2*$this->mark_abs_hsize, + $colwidth[$i % $numcolumns]); + } + + // Get the total width + $mtw = 0; + for( $i=0; $i < $numcolumns; ++$i ) { + $mtw += $colwidth[$i] ; + } + + // remove the last rows interpace margin (since there is no next row) + $abs_height -= $this->ylinespacing; + + + // Find out maximum width we need for legend box + $abs_width = $mtw+$this->xlmargin+($numcolumns-1)*$this->mark_abs_hsize; + + if( $this->xabspos === -1 && $this->yabspos === -1 ) { + $this->xabspos = $this->xpos*$aImg->width ; + $this->yabspos = $this->ypos*$aImg->height ; + } + + // Positioning of the legend box + if( $this->halign == 'left' ) { + $xp = $this->xabspos; + } + elseif( $this->halign == 'center' ) { + $xp = $this->xabspos - $abs_width/2; + } + else { + $xp = $aImg->width - $this->xabspos - $abs_width; + } + + $yp=$this->yabspos; + if( $this->valign == 'center' ) { + $yp-=$abs_height/2; + } + elseif( $this->valign == 'bottom' ) { + $yp-=$abs_height; + } + + // Stroke legend box + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->frameweight); + $aImg->SetLineStyle('solid'); + + if( $this->shadow ) { + $aImg->ShadowRectangle($xp,$yp, + $xp+$abs_width+$this->shadow_width+2, + $yp+$abs_height+$this->shadow_width+2, + $this->fill_color,$this->shadow_width+2,$this->shadow_color); + } + else { + $aImg->SetColor($this->fill_color); + $aImg->FilledRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); + $aImg->SetColor($this->color); + $aImg->Rectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); + } + + if( $this->bkg_gradtype >= 0 ) { + $grad = new Gradient($aImg); + $grad->FilledRectangle($xp+1, $yp+1, + $xp+$abs_width-3, $yp+$abs_height-3, + $this->bkg_gradfrom, $this->bkg_gradto, + $this->bkg_gradtype); + } + + // x1,y1 is the position for the legend marker + text + // The vertical position is the baseline position for the text + // and every marker is adjusted acording to that. + + // For multiline texts this get more complicated. + + $x1 = $xp + $this->xlmargin; + $y1 = $yp + $rowheight[0] - $this->ylinespacing + 2 ; // The ymargin is included in rowheight + + // Now, y1 is the bottom vertical position of the first legend, i.e if + // the legend has multiple lines it is the bottom line. + + $grad = new Gradient($aImg); + $patternFactory = null; + + // Now stroke each legend in turn + // Each plot has added the following information to the legend + // p[0] = Legend text + // p[1] = Color, + // p[2] = For markers a reference to the PlotMark object + // p[3] = For lines the line style, for gradient the negative gradient style + // p[4] = CSIM target + // p[5] = CSIM Alt text + $i = 1 ; $row = 0; + foreach($this->txtcol as $p) { + + // STROKE DEBUG BOX + if( _JPG_DEBUG ) { + $aImg->SetLineWeight(1); + $aImg->SetColor('red'); + $aImg->SetLineStyle('solid'); + $aImg->Rectangle($x1,$y1,$xp+$abs_width-1,$y1-$rowheight[$row]); + } + + $aImg->SetLineWeight($this->weight); + $x1 = round($x1)+1; // We add one to not collide with the border + $y1=round($y1); + + // This is the center offset up from the baseline which is + // considered the "center" of the marks. This gets slightly complicated since + // we need to consider if the text is a multiline paragraph or if it is only + // a single line. The reason is that for single line the y1 corresponds to the baseline + // and that is fine. However for a multiline paragraph there is no single baseline + // and in that case the y1 corresponds to the lowest y for the bounding box. In that + // case we center the mark in the middle of the paragraph + if( !preg_match('/\n/',$p[0]) ) { + // Single line + $marky = ceil($y1-$this->mark_abs_vsize/2)-1; + } else { + // Paragraph + $marky = $y1 - $aImg->GetTextHeight($p[0])/2; + + // echo "y1=$y1, p[o]={$p[0]}, marky=$marky
      "; + } + + //echo "
      Mark #$i: marky=$marky
      "; + + $x1 += $this->mark_abs_hsize; + + if ( !empty($p[2]) && $p[2]->GetType() > -1 ) { + + + // Make a plot mark legend. This is constructed with a mark which + // is run through with a line + + // First construct a bit of the line that looks exactly like the + // line in the plot + $aImg->SetColor($p[1]); + if( is_string($p[3]) || $p[3]>0 ) { + $aImg->SetLineStyle($p[3]); + $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky,$x1+$this->mark_abs_hsize,$marky); + } + + // Stroke a mark with the standard size + // (As long as it is not an image mark ) + if( $p[2]->GetType() != MARK_IMG ) { + + // Clear any user callbacks since we ont want them called for + // the legend marks + $p[2]->iFormatCallback = ''; + $p[2]->iFormatCallback2 = ''; + + // Since size for circles is specified as the radius + // this means that we must half the size to make the total + // width behave as the other marks + if( $p[2]->GetType() == MARK_FILLEDCIRCLE || $p[2]->GetType() == MARK_CIRCLE ) { + $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)/2); + $p[2]->Stroke($aImg,$x1,$marky); + } + else { + $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)); + $p[2]->Stroke($aImg,$x1,$marky); + } + } + } + elseif ( !empty($p[2]) && (is_string($p[3]) || $p[3]>0 ) ) { + // Draw a styled line + $aImg->SetColor($p[1]); + $aImg->SetLineStyle($p[3]); + $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky,$x1+$this->mark_abs_hsize,$marky); + $aImg->StyleLine($x1-$this->mark_abs_hsize,$marky+1,$x1+$this->mark_abs_hsize,$marky+1); + } + else { + // Draw a colored box + $color = $p[1] ; + + // We make boxes slightly larger to better show + $boxsize = max($this->mark_abs_vsize,$this->mark_abs_hsize) + 2 ; + + $ym = $marky-ceil($boxsize/2) ; // Marker y-coordinate + + // We either need to plot a gradient or a + // pattern. To differentiate we use a kludge. + // Patterns have a p[3] value of < -100 + if( $p[3] < -100 ) { + // p[1][0] == iPattern, p[1][1] == iPatternColor, p[1][2] == iPatternDensity + if( $patternFactory == null ) { + $patternFactory = new RectPatternFactory(); + } + $prect = $patternFactory->Create($p[1][0],$p[1][1],1); + $prect->SetBackground($p[1][3]); + $prect->SetDensity($p[1][2]+1); + $prect->SetPos(new Rectangle($x1,$ym,$boxsize,$boxsize)); + $prect->Stroke($aImg); + $prect=null; + } + else { + if( is_array($color) && count($color)==2 ) { + // The client want a gradient color + $grad->FilledRectangle($x1-$boxsize/2,$ym, + $x1+$boxsize/2,$ym+$boxsize, + $color[0],$color[1],-$p[3]); + } + else { + $aImg->SetColor($p[1]); + $aImg->FilledRectangle($x1-$boxsize/2,$ym, + $x1+$boxsize/2,$ym+$boxsize); + } + $aImg->SetColor($this->color); + $aImg->SetLineWeight($fillBoxFrameWeight); + $aImg->Rectangle($x1-$boxsize/2,$ym, + $x1+$boxsize/2,$ym+$boxsize); + } + } + $aImg->SetColor($this->font_color); + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetTextAlign('left','baseline'); + + $debug=false; + $aImg->StrokeText($x1+$this->mark_abs_hsize+$this->xmargin,$y1,$p[0], + 0,'left',$debug); + + // Add CSIM for Legend if defined + if( !empty($p[4]) ) { + + $xs = $x1 - $this->mark_abs_hsize ; + $ys = $y1 + 1 ; + $xe = $x1 + $aImg->GetTextWidth($p[0]) + $this->mark_abs_hsize + $this->xmargin ; + $ye = $y1-$rowheight[$row]+1; + $coords = "$xs,$ys,$xe,$y1,$xe,$ye,$xs,$ye"; + if( ! empty($p[4]) ) { + $this->csimareas .= "csimareas .= " target=\"".$p[6]."\""; + } + + if( !empty($p[5]) ) { + $tmp=sprintf($p[5],$p[0]); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + if( $i >= $this->layout_n ) { + $x1 = $xp+$this->xlmargin; + $row++; + if( !empty($rowheight[$row]) ) + $y1 += $rowheight[$row]; + $i = 1; + } + else { + $x1 += $colwidth[($i-1) % $numcolumns] ; + ++$i; + } + } + } +} // Class + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_line.php b/ext/jpgraph-3.0.7/src/jpgraph_line.php index 64d2dc5..3ecb386 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_line.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_line.php @@ -1,682 +1,682 @@ -mark = new PlotMark() ; - $this->color = ColorFactory::getColor(); - $this->fill_color = $this->color; - } - //--------------- - // PUBLIC METHODS - - function SetFilled($aFlg=true) { - $this->filled = $aFlg; - } - - function SetBarCenter($aFlag=true) { - $this->barcenter=$aFlag; - } - - function SetStyle($aStyle) { - $this->line_style=$aStyle; - } - - function SetStepStyle($aFlag=true) { - $this->step_style = $aFlag; - } - - function SetColor($aColor) { - parent::SetColor($aColor); - } - - function SetFillFromYMin($f=true) { - $this->fillFromMin = $f ; - } - - function SetFillFromYMax($f=true) { - $this->fillFromMax = $f ; - } - - function SetFillColor($aColor,$aFilled=true) { - //$this->color = $aColor; - $this->fill_color=$aColor; - $this->filled=$aFilled; - } - - function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) { - $this->fillgrad_fromcolor = $aFromColor; - $this->fillgrad_tocolor = $aToColor; - $this->fillgrad_numcolors = $aNumColors; - $this->filled = $aFilled; - $this->fillgrad = true; - } - - function Legend($graph) { - if( $this->legend!="" ) { - if( $this->filled && !$this->fillgrad ) { - $graph->legend->Add($this->legend, - $this->fill_color,$this->mark,0, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - elseif( $this->fillgrad ) { - $color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor); - // In order to differentiate between gradients and cooors specified as an RGB triple - $graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } else { - $graph->legend->Add($this->legend, - $this->color,$this->mark,$this->line_style, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - } - } - - function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) { - if($aMin > $aMax) { - // swap - $tmp = $aMin; - $aMin = $aMax; - $aMax = $tmp; - } - $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder); - } - - // Gets called before any axis are stroked - function PreStrokeAdjust($graph) { - - // If another plot type have already adjusted the - // offset we don't touch it. - // (We check for empty in case the scale is a log scale - // and hence doesn't contain any xlabel_offset) - if( empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { - if( $this->center ) { - ++$this->numpoints; - $a=0.5; $b=0.5; - } else { - $a=0; $b=0; - } - $graph->xaxis->scale->ticks->SetXLabelOffset($a); - $graph->SetTextScaleOff($b); - //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); - } - } - - function SetFastStroke($aFlg=true) { - $this->iFastStroke = $aFlg; - } - - function FastStroke($img,$xscale,$yscale,$aStartPoint=0,$exist_x=true) { - // An optimized stroke for many data points with no extra - // features but 60% faster. You can't have values or line styles, or null - // values in plots. - $numpoints=count($this->coords[0]); - if( $this->barcenter ) { - $textadj = 0.5-$xscale->text_scale_off; - } - else { - $textadj = 0; - } - - $img->SetColor($this->color); - $img->SetLineWeight($this->weight); - $pnts=$aStartPoint; - while( $pnts < $numpoints ) { - if( $exist_x ) { - $x=$this->coords[1][$pnts]; - } - else { - $x=$pnts+$textadj; - } - $xt = $xscale->Translate($x); - $y=$this->coords[0][$pnts]; - $yt = $yscale->Translate($y); - if( is_numeric($y) ) { - $cord[] = $xt; - $cord[] = $yt; - } - elseif( $y == '-' && $pnts > 0 ) { - // Just ignore - } - else { - JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()'); - } - ++$pnts; - } // WHILE - - $img->Polygon($cord,false,true); - } - - function Stroke($img,$xscale,$yscale) { - $idx=0; - $numpoints=count($this->coords[0]); - if( isset($this->coords[1]) ) { - if( count($this->coords[1])!=$numpoints ) { - JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); - //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); - } - else { - $exist_x = true; - } - } - else { - $exist_x = false; - } - - if( $this->barcenter ) { - $textadj = 0.5-$xscale->text_scale_off; - } - else { - $textadj = 0; - } - - // Find the first numeric data point - $startpoint=0; - while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) ) { - ++$startpoint; - } - - // Bail out if no data points - if( $startpoint == $numpoints ) return; - - if( $this->iFastStroke ) { - $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x); - return; - } - - if( $exist_x ) { - $xs=$this->coords[1][$startpoint]; - } - else { - $xs= $textadj+$startpoint; - } - - $img->SetStartPoint($xscale->Translate($xs), - $yscale->Translate($this->coords[0][$startpoint])); - - if( $this->filled ) { - if( $this->fillFromMax ) { - //$max = $yscale->GetMaxVal(); - $cord[$idx++] = $xscale->Translate($xs); - $cord[$idx++] = $yscale->scale_abs[1]; - } - else { - $min = $yscale->GetMinVal(); - if( $min > 0 || $this->fillFromMin ) { - $fillmin = $yscale->scale_abs[0];//Translate($min); - } - else { - $fillmin = $yscale->Translate(0); - } - - $cord[$idx++] = $xscale->Translate($xs); - $cord[$idx++] = $fillmin; - } - } - $xt = $xscale->Translate($xs); - $yt = $yscale->Translate($this->coords[0][$startpoint]); - $cord[$idx++] = $xt; - $cord[$idx++] = $yt; - $yt_old = $yt; - $xt_old = $xt; - $y_old = $this->coords[0][$startpoint]; - - $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt); - - $img->SetColor($this->color); - $img->SetLineWeight($this->weight); - $img->SetLineStyle($this->line_style); - $pnts=$startpoint+1; - $firstnonumeric = false; - - - while( $pnts < $numpoints ) { - - if( $exist_x ) { - $x=$this->coords[1][$pnts]; - } - else { - $x=$pnts+$textadj; - } - $xt = $xscale->Translate($x); - $yt = $yscale->Translate($this->coords[0][$pnts]); - - $y=$this->coords[0][$pnts]; - if( $this->step_style ) { - // To handle null values within step style we need to record the - // first non numeric value so we know from where to start if the - // non value is '-'. - if( is_numeric($y) ) { - $firstnonumeric = false; - if( is_numeric($y_old) ) { - $img->StyleLine($xt_old,$yt_old,$xt,$yt_old); - $img->StyleLine($xt,$yt_old,$xt,$yt); - } - elseif( $y_old == '-' ) { - $img->StyleLine($xt_first,$yt_first,$xt,$yt_first); - $img->StyleLine($xt,$yt_first,$xt,$yt); - } - else { - $yt_old = $yt; - $xt_old = $xt; - } - $cord[$idx++] = $xt; - $cord[$idx++] = $yt_old; - $cord[$idx++] = $xt; - $cord[$idx++] = $yt; - } - elseif( $firstnonumeric==false ) { - $firstnonumeric = true; - $yt_first = $yt_old; - $xt_first = $xt_old; - } - } - else { - $tmp1=$y; - $prev=$this->coords[0][$pnts-1]; - if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x'; - if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x'; - - if( is_numeric($y) || (is_string($y) && $y != '-') ) { - if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) { - $img->StyleLineTo($xt,$yt); - } - else { - $img->SetStartPoint($xt,$yt); - } - } - if( $this->filled && $tmp1 !== '-' ) { - if( $tmp1 === 'x' ) { - $cord[$idx++] = $cord[$idx-3]; - $cord[$idx++] = $fillmin; - } - elseif( $prev === 'x' ) { - $cord[$idx++] = $xt; - $cord[$idx++] = $fillmin; - $cord[$idx++] = $xt; - $cord[$idx++] = $yt; - } - else { - $cord[$idx++] = $xt; - $cord[$idx++] = $yt; - } - } - else { - if( is_numeric($tmp1) && (is_numeric($prev) || $prev === '-' ) ) { - $cord[$idx++] = $xt; - $cord[$idx++] = $yt; - } - } - } - $yt_old = $yt; - $xt_old = $xt; - $y_old = $y; - - $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); - - ++$pnts; - } - - if( $this->filled ) { - $cord[$idx++] = $xt; - if( $this->fillFromMax ) { - $cord[$idx++] = $yscale->scale_abs[1]; - } - else { - if( $min > 0 || $this->fillFromMin ) { - $cord[$idx++] = $yscale->Translate($min); - } - else { - $cord[$idx++] = $yscale->Translate(0); - } - } - if( $this->fillgrad ) { - $img->SetLineWeight(1); - $grad = new Gradient($img); - $grad->SetNumColors($this->fillgrad_numcolors); - $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor); - $img->SetLineWeight($this->weight); - } - else { - $img->SetColor($this->fill_color); - $img->FilledPolygon($cord); - } - if( $this->weight > 0 ) { - $img->SetLineWeight($this->weight); - $img->SetColor($this->color); - // Remove first and last coordinate before drawing the line - // sine we otherwise get the vertical start and end lines which - // doesn't look appropriate - $img->Polygon(array_slice($cord,2,count($cord)-4)); - } - } - - if(!empty($this->filledAreas)) { - - $minY = $yscale->Translate($yscale->GetMinVal()); - $factor = ($this->step_style ? 4 : 2); - - for($i = 0; $i < sizeof($this->filledAreas); ++$i) { - // go through all filled area elements ordered by insertion - // fill polygon array - $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor]; - $areaCoords[] = $minY; - - $areaCoords = - array_merge($areaCoords, - array_slice($cord, - $this->filledAreas[$i][0] * $factor, - ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor)); - $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x - $areaCoords[] = $minY; // last y - - if($this->filledAreas[$i][3]) { - $img->SetColor($this->filledAreas[$i][2]); - $img->FilledPolygon($areaCoords); - $img->SetColor($this->color); - } - // Check if we should draw the frame. - // If not we still re-draw the line since it might have been - // partially overwritten by the filled area and it doesn't look - // very good. - if( $this->filledAreas[$i][4] ) { - $img->Polygon($areaCoords); - } - else { - $img->Polygon($cord); - } - - $areaCoords = array(); - } - } - - if( $this->mark->type == -1 || $this->mark->show == false ) - return; - - for( $pnts=0; $pnts<$numpoints; ++$pnts) { - - if( $exist_x ) { - $x=$this->coords[1][$pnts]; - } - else { - $x=$pnts+$textadj; - } - $xt = $xscale->Translate($x); - $yt = $yscale->Translate($this->coords[0][$pnts]); - - if( is_numeric($this->coords[0][$pnts]) ) { - if( !empty($this->csimtargets[$pnts]) ) { - if( !empty($this->csimwintargets[$pnts]) ) { - $this->mark->SetCSIMTarget($this->csimtargets[$pnts],$this->csimwintargets[$pnts]); - } - else { - $this->mark->SetCSIMTarget($this->csimtargets[$pnts]); - } - $this->mark->SetCSIMAlt($this->csimalts[$pnts]); - } - if( $exist_x ) { - $x=$this->coords[1][$pnts]; - } - else { - $x=$pnts; - } - $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x); - $this->mark->Stroke($img,$xt,$yt); - $this->csimareas .= $this->mark->GetCSIMAreas(); - } - } - } -} // Class - - -//=================================================== -// CLASS AccLinePlot -// Description: -//=================================================== -class AccLinePlot extends Plot { - protected $plots=null,$nbrplots=0; - private $iStartEndZero=true; - //--------------- - // CONSTRUCTOR - function __construct($plots) { - $this->plots = $plots; - $this->nbrplots = count($plots); - $this->numpoints = $plots[0]->numpoints; - - // Verify that all plots have the same number of data points - for( $i=1; $i < $this->nbrplots; ++$i ) { - if( $plots[$i]->numpoints != $this->numpoints ) { - JpGraphError::RaiseL(10003);//('Each plot in an accumulated lineplot must have the same number of data points',0) - } - } - - for($i=0; $i < $this->nbrplots; ++$i ) { - $this->LineInterpolate($this->plots[$i]->coords[0]); - } - } - - //--------------- - // PUBLIC METHODS - function Legend($graph) { - foreach( $this->plots as $p ) { - $p->DoLegend($graph); - } - } - - function Max() { - list($xmax) = $this->plots[0]->Max(); - $nmax=0; - $n = count($this->plots); - for($i=0; $i < $n; ++$i) { - $nc = count($this->plots[$i]->coords[0]); - $nmax = max($nmax,$nc); - list($x) = $this->plots[$i]->Max(); - $xmax = Max($xmax,$x); - } - for( $i = 0; $i < $nmax; $i++ ) { - // Get y-value for line $i by adding the - // individual bars from all the plots added. - // It would be wrong to just add the - // individual plots max y-value since that - // would in most cases give to large y-value. - $y=$this->plots[0]->coords[0][$i]; - for( $j = 1; $j < $this->nbrplots; $j++ ) { - $y += $this->plots[ $j ]->coords[0][$i]; - } - $ymax[$i] = $y; - } - $ymax = max($ymax); - return array($xmax,$ymax); - } - - function Min() { - $nmax=0; - list($xmin,$ysetmin) = $this->plots[0]->Min(); - $n = count($this->plots); - for($i=0; $i < $n; ++$i) { - $nc = count($this->plots[$i]->coords[0]); - $nmax = max($nmax,$nc); - list($x,$y) = $this->plots[$i]->Min(); - $xmin = Min($xmin,$x); - $ysetmin = Min($y,$ysetmin); - } - for( $i = 0; $i < $nmax; $i++ ) { - // Get y-value for line $i by adding the - // individual bars from all the plots added. - // It would be wrong to just add the - // individual plots min y-value since that - // would in most cases give to small y-value. - $y=$this->plots[0]->coords[0][$i]; - for( $j = 1; $j < $this->nbrplots; $j++ ) { - $y += $this->plots[ $j ]->coords[0][$i]; - } - $ymin[$i] = $y; - } - $ymin = Min($ysetmin,Min($ymin)); - return array($xmin,$ymin); - } - - // Gets called before any axis are stroked - function PreStrokeAdjust($graph) { - - // If another plot type have already adjusted the - // offset we don't touch it. - // (We check for empty in case the scale is a log scale - // and hence doesn't contain any xlabel_offset) - - if( empty($graph->xaxis->scale->ticks->xlabel_offset) || - $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { - if( $this->center ) { - ++$this->numpoints; - $a=0.5; $b=0.5; - } else { - $a=0; $b=0; - } - $graph->xaxis->scale->ticks->SetXLabelOffset($a); - $graph->SetTextScaleOff($b); - $graph->xaxis->scale->ticks->SupressMinorTickMarks(); - } - - } - - function SetInterpolateMode($aIntMode) { - $this->iStartEndZero=$aIntMode; - } - - // Replace all '-' with an interpolated value. We use straightforward - // linear interpolation. If the data starts with one or several '-' they - // will be replaced by the the first valid data point - function LineInterpolate(&$aData) { - - $n=count($aData); - $i=0; - - // If first point is undefined we will set it to the same as the first - // valid data - if( $aData[$i]==='-' ) { - // Find the first valid data - while( $i < $n && $aData[$i]==='-' ) { - ++$i; - } - if( $i < $n ) { - for($j=0; $j < $i; ++$j ) { - if( $this->iStartEndZero ) - $aData[$i] = 0; - else - $aData[$j] = $aData[$i]; - } - } - else { - // All '-' => Error - return false; - } - } - - while($i < $n) { - while( $i < $n && $aData[$i] !== '-' ) { - ++$i; - } - if( $i < $n ) { - $pstart=$i-1; - - // Now see how long this segment of '-' are - while( $i < $n && $aData[$i] === '-' ) { - ++$i; - } - if( $i < $n ) { - $pend=$i; - $size=$pend-$pstart; - $k=($aData[$pend]-$aData[$pstart])/$size; - // Replace the segment of '-' with a linear interpolated value. - for($j=1; $j < $size; ++$j ) { - $aData[$pstart+$j] = $aData[$pstart] + $j*$k ; - } - } - else { - // There are no valid end point. The '-' goes all the way to the end - // In that case we just set all the remaining values the the same as the - // last valid data point. - for( $j=$pstart+1; $j < $n; ++$j ) - if( $this->iStartEndZero ) { - $aData[$j] = 0; - } - else { - $aData[$j] = $aData[$pstart] ; - } - } - } - } - return true; - } - - // To avoid duplicate of line drawing code here we just - // change the y-values for each plot and then restore it - // after we have made the stroke. We must do this copy since - // it wouldn't be possible to create an acc line plot - // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl)); - // since this method would have a side effect. - function Stroke($img,$xscale,$yscale) { - $img->SetLineWeight($this->weight); - $this->numpoints = count($this->plots[0]->coords[0]); - // Allocate array - $coords[$this->nbrplots][$this->numpoints]=0; - for($i=0; $i<$this->numpoints; $i++) { - $coords[0][$i]=$this->plots[0]->coords[0][$i]; - $accy=$coords[0][$i]; - for($j=1; $j<$this->nbrplots; ++$j ) { - $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; - $accy = $coords[$j][$i]; - } - } - for($j=$this->nbrplots-1; $j>=0; --$j) { - $p=$this->plots[$j]; - for( $i=0; $i<$this->numpoints; ++$i) { - $tmp[$i]=$p->coords[0][$i]; - $p->coords[0][$i]=$coords[$j][$i]; - } - $p->Stroke($img,$xscale,$yscale); - for( $i=0; $i<$this->numpoints; ++$i) { - $p->coords[0][$i]=$tmp[$i]; - } - $p->coords[0][]=$tmp; - } - } -} // Class - - -/* EOF */ -?> +mark = new PlotMark() ; + $this->color = ColorFactory::getColor(); + $this->fill_color = $this->color; + } + //--------------- + // PUBLIC METHODS + + function SetFilled($aFlg=true) { + $this->filled = $aFlg; + } + + function SetBarCenter($aFlag=true) { + $this->barcenter=$aFlag; + } + + function SetStyle($aStyle) { + $this->line_style=$aStyle; + } + + function SetStepStyle($aFlag=true) { + $this->step_style = $aFlag; + } + + function SetColor($aColor) { + parent::SetColor($aColor); + } + + function SetFillFromYMin($f=true) { + $this->fillFromMin = $f ; + } + + function SetFillFromYMax($f=true) { + $this->fillFromMax = $f ; + } + + function SetFillColor($aColor,$aFilled=true) { + //$this->color = $aColor; + $this->fill_color=$aColor; + $this->filled=$aFilled; + } + + function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) { + $this->fillgrad_fromcolor = $aFromColor; + $this->fillgrad_tocolor = $aToColor; + $this->fillgrad_numcolors = $aNumColors; + $this->filled = $aFilled; + $this->fillgrad = true; + } + + function Legend($graph) { + if( $this->legend!="" ) { + if( $this->filled && !$this->fillgrad ) { + $graph->legend->Add($this->legend, + $this->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + elseif( $this->fillgrad ) { + $color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor); + // In order to differentiate between gradients and cooors specified as an RGB triple + $graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } else { + $graph->legend->Add($this->legend, + $this->color,$this->mark,$this->line_style, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + } + + function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) { + if($aMin > $aMax) { + // swap + $tmp = $aMin; + $aMin = $aMax; + $aMax = $tmp; + } + $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder); + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + + // If another plot type have already adjusted the + // offset we don't touch it. + // (We check for empty in case the scale is a log scale + // and hence doesn't contain any xlabel_offset) + if( empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { + if( $this->center ) { + ++$this->numpoints; + $a=0.5; $b=0.5; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + } + + function SetFastStroke($aFlg=true) { + $this->iFastStroke = $aFlg; + } + + function FastStroke($img,$xscale,$yscale,$aStartPoint=0,$exist_x=true) { + // An optimized stroke for many data points with no extra + // features but 60% faster. You can't have values or line styles, or null + // values in plots. + $numpoints=count($this->coords[0]); + if( $this->barcenter ) { + $textadj = 0.5-$xscale->text_scale_off; + } + else { + $textadj = 0; + } + + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $pnts=$aStartPoint; + while( $pnts < $numpoints ) { + if( $exist_x ) { + $x=$this->coords[1][$pnts]; + } + else { + $x=$pnts+$textadj; + } + $xt = $xscale->Translate($x); + $y=$this->coords[0][$pnts]; + $yt = $yscale->Translate($y); + if( is_numeric($y) ) { + $cord[] = $xt; + $cord[] = $yt; + } + elseif( $y == '-' && $pnts > 0 ) { + // Just ignore + } + else { + JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()'); + } + ++$pnts; + } // WHILE + + $img->Polygon($cord,false,true); + } + + function Stroke($img,$xscale,$yscale) { + $idx=0; + $numpoints=count($this->coords[0]); + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) { + JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); + //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + } + else { + $exist_x = true; + } + } + else { + $exist_x = false; + } + + if( $this->barcenter ) { + $textadj = 0.5-$xscale->text_scale_off; + } + else { + $textadj = 0; + } + + // Find the first numeric data point + $startpoint=0; + while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) ) { + ++$startpoint; + } + + // Bail out if no data points + if( $startpoint == $numpoints ) return; + + if( $this->iFastStroke ) { + $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x); + return; + } + + if( $exist_x ) { + $xs=$this->coords[1][$startpoint]; + } + else { + $xs= $textadj+$startpoint; + } + + $img->SetStartPoint($xscale->Translate($xs), + $yscale->Translate($this->coords[0][$startpoint])); + + if( $this->filled ) { + if( $this->fillFromMax ) { + //$max = $yscale->GetMaxVal(); + $cord[$idx++] = $xscale->Translate($xs); + $cord[$idx++] = $yscale->scale_abs[1]; + } + else { + $min = $yscale->GetMinVal(); + if( $min > 0 || $this->fillFromMin ) { + $fillmin = $yscale->scale_abs[0];//Translate($min); + } + else { + $fillmin = $yscale->Translate(0); + } + + $cord[$idx++] = $xscale->Translate($xs); + $cord[$idx++] = $fillmin; + } + } + $xt = $xscale->Translate($xs); + $yt = $yscale->Translate($this->coords[0][$startpoint]); + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + $yt_old = $yt; + $xt_old = $xt; + $y_old = $this->coords[0][$startpoint]; + + $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt); + + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $img->SetLineStyle($this->line_style); + $pnts=$startpoint+1; + $firstnonumeric = false; + + + while( $pnts < $numpoints ) { + + if( $exist_x ) { + $x=$this->coords[1][$pnts]; + } + else { + $x=$pnts+$textadj; + } + $xt = $xscale->Translate($x); + $yt = $yscale->Translate($this->coords[0][$pnts]); + + $y=$this->coords[0][$pnts]; + if( $this->step_style ) { + // To handle null values within step style we need to record the + // first non numeric value so we know from where to start if the + // non value is '-'. + if( is_numeric($y) ) { + $firstnonumeric = false; + if( is_numeric($y_old) ) { + $img->StyleLine($xt_old,$yt_old,$xt,$yt_old); + $img->StyleLine($xt,$yt_old,$xt,$yt); + } + elseif( $y_old == '-' ) { + $img->StyleLine($xt_first,$yt_first,$xt,$yt_first); + $img->StyleLine($xt,$yt_first,$xt,$yt); + } + else { + $yt_old = $yt; + $xt_old = $xt; + } + $cord[$idx++] = $xt; + $cord[$idx++] = $yt_old; + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + elseif( $firstnonumeric==false ) { + $firstnonumeric = true; + $yt_first = $yt_old; + $xt_first = $xt_old; + } + } + else { + $tmp1=$y; + $prev=$this->coords[0][$pnts-1]; + if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x'; + if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x'; + + if( is_numeric($y) || (is_string($y) && $y != '-') ) { + if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) { + $img->StyleLineTo($xt,$yt); + } + else { + $img->SetStartPoint($xt,$yt); + } + } + if( $this->filled && $tmp1 !== '-' ) { + if( $tmp1 === 'x' ) { + $cord[$idx++] = $cord[$idx-3]; + $cord[$idx++] = $fillmin; + } + elseif( $prev === 'x' ) { + $cord[$idx++] = $xt; + $cord[$idx++] = $fillmin; + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + else { + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + } + else { + if( is_numeric($tmp1) && (is_numeric($prev) || $prev === '-' ) ) { + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + } + } + $yt_old = $yt; + $xt_old = $xt; + $y_old = $y; + + $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); + + ++$pnts; + } + + if( $this->filled ) { + $cord[$idx++] = $xt; + if( $this->fillFromMax ) { + $cord[$idx++] = $yscale->scale_abs[1]; + } + else { + if( $min > 0 || $this->fillFromMin ) { + $cord[$idx++] = $yscale->Translate($min); + } + else { + $cord[$idx++] = $yscale->Translate(0); + } + } + if( $this->fillgrad ) { + $img->SetLineWeight(1); + $grad = new Gradient($img); + $grad->SetNumColors($this->fillgrad_numcolors); + $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor); + $img->SetLineWeight($this->weight); + } + else { + $img->SetColor($this->fill_color); + $img->FilledPolygon($cord); + } + if( $this->weight > 0 ) { + $img->SetLineWeight($this->weight); + $img->SetColor($this->color); + // Remove first and last coordinate before drawing the line + // sine we otherwise get the vertical start and end lines which + // doesn't look appropriate + $img->Polygon(array_slice($cord,2,count($cord)-4)); + } + } + + if(!empty($this->filledAreas)) { + + $minY = $yscale->Translate($yscale->GetMinVal()); + $factor = ($this->step_style ? 4 : 2); + + for($i = 0; $i < sizeof($this->filledAreas); ++$i) { + // go through all filled area elements ordered by insertion + // fill polygon array + $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor]; + $areaCoords[] = $minY; + + $areaCoords = + array_merge($areaCoords, + array_slice($cord, + $this->filledAreas[$i][0] * $factor, + ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor)); + $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x + $areaCoords[] = $minY; // last y + + if($this->filledAreas[$i][3]) { + $img->SetColor($this->filledAreas[$i][2]); + $img->FilledPolygon($areaCoords); + $img->SetColor($this->color); + } + // Check if we should draw the frame. + // If not we still re-draw the line since it might have been + // partially overwritten by the filled area and it doesn't look + // very good. + if( $this->filledAreas[$i][4] ) { + $img->Polygon($areaCoords); + } + else { + $img->Polygon($cord); + } + + $areaCoords = array(); + } + } + + if( $this->mark->type == -1 || $this->mark->show == false ) + return; + + for( $pnts=0; $pnts<$numpoints; ++$pnts) { + + if( $exist_x ) { + $x=$this->coords[1][$pnts]; + } + else { + $x=$pnts+$textadj; + } + $xt = $xscale->Translate($x); + $yt = $yscale->Translate($this->coords[0][$pnts]); + + if( is_numeric($this->coords[0][$pnts]) ) { + if( !empty($this->csimtargets[$pnts]) ) { + if( !empty($this->csimwintargets[$pnts]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$pnts],$this->csimwintargets[$pnts]); + } + else { + $this->mark->SetCSIMTarget($this->csimtargets[$pnts]); + } + $this->mark->SetCSIMAlt($this->csimalts[$pnts]); + } + if( $exist_x ) { + $x=$this->coords[1][$pnts]; + } + else { + $x=$pnts; + } + $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x); + $this->mark->Stroke($img,$xt,$yt); + $this->csimareas .= $this->mark->GetCSIMAreas(); + } + } + } +} // Class + + +//=================================================== +// CLASS AccLinePlot +// Description: +//=================================================== +class AccLinePlot extends Plot { + protected $plots=null,$nbrplots=0; + private $iStartEndZero=true; + //--------------- + // CONSTRUCTOR + function __construct($plots) { + $this->plots = $plots; + $this->nbrplots = count($plots); + $this->numpoints = $plots[0]->numpoints; + + // Verify that all plots have the same number of data points + for( $i=1; $i < $this->nbrplots; ++$i ) { + if( $plots[$i]->numpoints != $this->numpoints ) { + JpGraphError::RaiseL(10003);//('Each plot in an accumulated lineplot must have the same number of data points',0) + } + } + + for($i=0; $i < $this->nbrplots; ++$i ) { + $this->LineInterpolate($this->plots[$i]->coords[0]); + } + } + + //--------------- + // PUBLIC METHODS + function Legend($graph) { + foreach( $this->plots as $p ) { + $p->DoLegend($graph); + } + } + + function Max() { + list($xmax) = $this->plots[0]->Max(); + $nmax=0; + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + $nc = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$nc); + list($x) = $this->plots[$i]->Max(); + $xmax = Max($xmax,$x); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for line $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots max y-value since that + // would in most cases give to large y-value. + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + $y += $this->plots[ $j ]->coords[0][$i]; + } + $ymax[$i] = $y; + } + $ymax = max($ymax); + return array($xmax,$ymax); + } + + function Min() { + $nmax=0; + list($xmin,$ysetmin) = $this->plots[0]->Min(); + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + $nc = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$nc); + list($x,$y) = $this->plots[$i]->Min(); + $xmin = Min($xmin,$x); + $ysetmin = Min($y,$ysetmin); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for line $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots min y-value since that + // would in most cases give to small y-value. + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + $y += $this->plots[ $j ]->coords[0][$i]; + } + $ymin[$i] = $y; + } + $ymin = Min($ysetmin,Min($ymin)); + return array($xmin,$ymin); + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + + // If another plot type have already adjusted the + // offset we don't touch it. + // (We check for empty in case the scale is a log scale + // and hence doesn't contain any xlabel_offset) + + if( empty($graph->xaxis->scale->ticks->xlabel_offset) || + $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { + if( $this->center ) { + ++$this->numpoints; + $a=0.5; $b=0.5; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + $graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + + } + + function SetInterpolateMode($aIntMode) { + $this->iStartEndZero=$aIntMode; + } + + // Replace all '-' with an interpolated value. We use straightforward + // linear interpolation. If the data starts with one or several '-' they + // will be replaced by the the first valid data point + function LineInterpolate(&$aData) { + + $n=count($aData); + $i=0; + + // If first point is undefined we will set it to the same as the first + // valid data + if( $aData[$i]==='-' ) { + // Find the first valid data + while( $i < $n && $aData[$i]==='-' ) { + ++$i; + } + if( $i < $n ) { + for($j=0; $j < $i; ++$j ) { + if( $this->iStartEndZero ) + $aData[$i] = 0; + else + $aData[$j] = $aData[$i]; + } + } + else { + // All '-' => Error + return false; + } + } + + while($i < $n) { + while( $i < $n && $aData[$i] !== '-' ) { + ++$i; + } + if( $i < $n ) { + $pstart=$i-1; + + // Now see how long this segment of '-' are + while( $i < $n && $aData[$i] === '-' ) { + ++$i; + } + if( $i < $n ) { + $pend=$i; + $size=$pend-$pstart; + $k=($aData[$pend]-$aData[$pstart])/$size; + // Replace the segment of '-' with a linear interpolated value. + for($j=1; $j < $size; ++$j ) { + $aData[$pstart+$j] = $aData[$pstart] + $j*$k ; + } + } + else { + // There are no valid end point. The '-' goes all the way to the end + // In that case we just set all the remaining values the the same as the + // last valid data point. + for( $j=$pstart+1; $j < $n; ++$j ) + if( $this->iStartEndZero ) { + $aData[$j] = 0; + } + else { + $aData[$j] = $aData[$pstart] ; + } + } + } + } + return true; + } + + // To avoid duplicate of line drawing code here we just + // change the y-values for each plot and then restore it + // after we have made the stroke. We must do this copy since + // it wouldn't be possible to create an acc line plot + // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl)); + // since this method would have a side effect. + function Stroke($img,$xscale,$yscale) { + $img->SetLineWeight($this->weight); + $this->numpoints = count($this->plots[0]->coords[0]); + // Allocate array + $coords[$this->nbrplots][$this->numpoints]=0; + for($i=0; $i<$this->numpoints; $i++) { + $coords[0][$i]=$this->plots[0]->coords[0][$i]; + $accy=$coords[0][$i]; + for($j=1; $j<$this->nbrplots; ++$j ) { + $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; + $accy = $coords[$j][$i]; + } + } + for($j=$this->nbrplots-1; $j>=0; --$j) { + $p=$this->plots[$j]; + for( $i=0; $i<$this->numpoints; ++$i) { + $tmp[$i]=$p->coords[0][$i]; + $p->coords[0][$i]=$coords[$j][$i]; + } + $p->Stroke($img,$xscale,$yscale); + for( $i=0; $i<$this->numpoints; ++$i) { + $p->coords[0][$i]=$tmp[$i]; + } + $p->coords[0][]=$tmp; + } + } +} // Class + + +/* EOF */ +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_log.php b/ext/jpgraph-3.0.7/src/jpgraph_log.php index af56034..8de08b1 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_log.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_log.php @@ -1,305 +1,305 @@ -ticks = new LogTicks(); - $this->name = 'log'; - } - - //---------------- - // PUBLIC METHODS - - // Translate between world and screen - function Translate($a) { - if( !is_numeric($a) ) { - if( $a != '' && $a != '-' && $a != 'x' ) { - JpGraphError::RaiseL(11001); - // ('Your data contains non-numeric values.'); - } - return 1; - } - if( $a < 0 ) { - JpGraphError::RaiseL(11002); - //("Negative data values can not be used in a log scale."); - exit(1); - } - if( $a==0 ) $a=1; - $a=log10($a); - return ceil($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); - } - - // Relative translate (don't include offset) usefull when we just want - // to know the relative position (in pixels) on the axis - function RelTranslate($a) { - if( !is_numeric($a) ) { - if( $a != '' && $a != '-' && $a != 'x' ) { - JpGraphError::RaiseL(11001); - //('Your data contains non-numeric values.'); - } - return 1; - } - if( $a==0 ) { - $a=1; - } - $a=log10($a); - return round(($a*1.0 - $this->scale[0]) * $this->scale_factor); - } - - // Use bcpow() for increased precision - function GetMinVal() { - if( function_exists("bcpow") ) { - return round(bcpow(10,$this->scale[0],15),14); - } - else { - return round(pow(10,$this->scale[0]),14); - } - } - - function GetMaxVal() { - if( function_exists("bcpow") ) { - return round(bcpow(10,$this->scale[1],15),14); - } - else { - return round(pow(10,$this->scale[1]),14); - } - } - - // Logarithmic autoscaling is much simplier since we just - // set the min and max to logs of the min and max values. - // Note that for log autoscale the "maxstep" the fourth argument - // isn't used. This is just included to give the method the same - // signature as the linear counterpart. - function AutoScale($img,$min,$max,$maxsteps,$majend=true) { - if( $min==0 ) $min=1; - - if( $max <= 0 ) { - JpGraphError::RaiseL(11004); - //('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.'); - } - if( is_numeric($this->autoscale_min) ) { - $smin = round($this->autoscale_min); - $smax = ceil(log10($max)); - if( $min >= $max ) { - JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); - } - } - else { - $smin = floor(log10($min)); - if( is_numeric($this->autoscale_max) ) { - $smax = round($this->autoscale_max); - if( $smin >= $smax ) { - JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); - } - } - else - $smax = ceil(log10($max)); - } - - $this->Update($img,$smin,$smax); - } - //--------------- - // PRIVATE METHODS -} // Class - -//=================================================== -// CLASS LogTicks -// Description: -//=================================================== -class LogTicks extends Ticks{ - private $label_logtype=LOGLABELS_MAGNITUDE; - private $ticklabels_pos = array(); - //--------------- - // CONSTRUCTOR - function LogTicks() { - } - //--------------- - // PUBLIC METHODS - function IsSpecified() { - return true; - } - - function SetLabelLogType($aType) { - $this->label_logtype = $aType; - } - - // For log scale it's meaningless to speak about a major step - // We just return -1 to make the framework happy (specifically - // StrokeLabels() ) - function GetMajor() { - return -1; - } - - function SetTextLabelStart($aStart) { - JpGraphError::RaiseL(11005); - //('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.'); - } - - function SetXLabelOffset($dummy) { - // For log scales we dont care about XLabel offset - } - - // Draw ticks on image "img" using scale "scale". The axis absolute - // position in the image is specified in pos, i.e. for an x-axis - // it specifies the absolute y-coord and for Y-ticks it specified the - // absolute x-position. - function Stroke($img,$scale,$pos) { - $start = $scale->GetMinVal(); - $limit = $scale->GetMaxVal(); - $nextMajor = 10*$start; - $step = $nextMajor / 10.0; - - - $img->SetLineWeight($this->weight); - - if( $scale->type == "y" ) { - // member direction specified if the ticks should be on - // left or right side. - $a=$pos + $this->direction*$this->GetMinTickAbsSize(); - $a2=$pos + $this->direction*$this->GetMajTickAbsSize(); - - $count=1; - $this->maj_ticks_pos[0]=$scale->Translate($start); - $this->maj_ticklabels_pos[0]=$scale->Translate($start); - if( $this->supress_first ) - $this->maj_ticks_label[0]=""; - else { - if( $this->label_formfunc != '' ) { - $f = $this->label_formfunc; - $this->maj_ticks_label[0]=call_user_func($f,$start); - } - elseif( $this->label_logtype == LOGLABELS_PLAIN ) { - $this->maj_ticks_label[0]=$start; - } - else { - $this->maj_ticks_label[0]='10^'.round(log10($start)); - } - } - $i=1; - for($y=$start; $y<=$limit; $y+=$step,++$count ) { - $ys=$scale->Translate($y); - $this->ticks_pos[]=$ys; - $this->ticklabels_pos[]=$ys; - if( $count % 10 == 0 ) { - if( !$this->supress_tickmarks ) { - if( $this->majcolor!="" ) { - $img->PushColor($this->majcolor); - $img->Line($pos,$ys,$a2,$ys); - $img->PopColor(); - } - else { - $img->Line($pos,$ys,$a2,$ys); - } - } - - $this->maj_ticks_pos[$i]=$ys; - $this->maj_ticklabels_pos[$i]=$ys; - - if( $this->label_formfunc != '' ) { - $f = $this->label_formfunc; - $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); - } - elseif( $this->label_logtype == 0 ) { - $this->maj_ticks_label[$i]=$nextMajor; - } - else { - $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); - } - ++$i; - $nextMajor *= 10; - $step *= 10; - $count=1; - } - else { - if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { - if( $this->mincolor!="" ) { - $img->PushColor($this->mincolor); - } - $img->Line($pos,$ys,$a,$ys); - if( $this->mincolor!="" ) { - $img->PopColor(); - } - } - } - } - } - else { - $a=$pos - $this->direction*$this->GetMinTickAbsSize(); - $a2=$pos - $this->direction*$this->GetMajTickAbsSize(); - $count=1; - $this->maj_ticks_pos[0]=$scale->Translate($start); - $this->maj_ticklabels_pos[0]=$scale->Translate($start); - if( $this->supress_first ) { - $this->maj_ticks_label[0]=""; - } - else { - if( $this->label_formfunc != '' ) { - $f = $this->label_formfunc; - $this->maj_ticks_label[0]=call_user_func($f,$start); - } - elseif( $this->label_logtype == 0 ) { - $this->maj_ticks_label[0]=$start; - } - else { - $this->maj_ticks_label[0]='10^'.round(log10($start)); - } - } - $i=1; - for($x=$start; $x<=$limit; $x+=$step,++$count ) { - $xs=$scale->Translate($x); - $this->ticks_pos[]=$xs; - $this->ticklabels_pos[]=$xs; - if( $count % 10 == 0 ) { - if( !$this->supress_tickmarks ) { - $img->Line($xs,$pos,$xs,$a2); - } - $this->maj_ticks_pos[$i]=$xs; - $this->maj_ticklabels_pos[$i]=$xs; - - if( $this->label_formfunc != '' ) { - $f = $this->label_formfunc; - $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); - } - elseif( $this->label_logtype == 0 ) { - $this->maj_ticks_label[$i]=$nextMajor; - } - else { - $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); - } - ++$i; - $nextMajor *= 10; - $step *= 10; - $count=1; - } - else { - if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { - $img->Line($xs,$pos,$xs,$a); - } - } - } - } - return true; - } -} // Class -/* EOF */ -?> +ticks = new LogTicks(); + $this->name = 'log'; + } + + //---------------- + // PUBLIC METHODS + + // Translate between world and screen + function Translate($a) { + if( !is_numeric($a) ) { + if( $a != '' && $a != '-' && $a != 'x' ) { + JpGraphError::RaiseL(11001); + // ('Your data contains non-numeric values.'); + } + return 1; + } + if( $a < 0 ) { + JpGraphError::RaiseL(11002); + //("Negative data values can not be used in a log scale."); + exit(1); + } + if( $a==0 ) $a=1; + $a=log10($a); + return ceil($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); + } + + // Relative translate (don't include offset) usefull when we just want + // to know the relative position (in pixels) on the axis + function RelTranslate($a) { + if( !is_numeric($a) ) { + if( $a != '' && $a != '-' && $a != 'x' ) { + JpGraphError::RaiseL(11001); + //('Your data contains non-numeric values.'); + } + return 1; + } + if( $a==0 ) { + $a=1; + } + $a=log10($a); + return round(($a*1.0 - $this->scale[0]) * $this->scale_factor); + } + + // Use bcpow() for increased precision + function GetMinVal() { + if( function_exists("bcpow") ) { + return round(bcpow(10,$this->scale[0],15),14); + } + else { + return round(pow(10,$this->scale[0]),14); + } + } + + function GetMaxVal() { + if( function_exists("bcpow") ) { + return round(bcpow(10,$this->scale[1],15),14); + } + else { + return round(pow(10,$this->scale[1]),14); + } + } + + // Logarithmic autoscaling is much simplier since we just + // set the min and max to logs of the min and max values. + // Note that for log autoscale the "maxstep" the fourth argument + // isn't used. This is just included to give the method the same + // signature as the linear counterpart. + function AutoScale($img,$min,$max,$maxsteps,$majend=true) { + if( $min==0 ) $min=1; + + if( $max <= 0 ) { + JpGraphError::RaiseL(11004); + //('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.'); + } + if( is_numeric($this->autoscale_min) ) { + $smin = round($this->autoscale_min); + $smax = ceil(log10($max)); + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + } + else { + $smin = floor(log10($min)); + if( is_numeric($this->autoscale_max) ) { + $smax = round($this->autoscale_max); + if( $smin >= $smax ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + } + else + $smax = ceil(log10($max)); + } + + $this->Update($img,$smin,$smax); + } + //--------------- + // PRIVATE METHODS +} // Class + +//=================================================== +// CLASS LogTicks +// Description: +//=================================================== +class LogTicks extends Ticks{ + private $label_logtype=LOGLABELS_MAGNITUDE; + private $ticklabels_pos = array(); + //--------------- + // CONSTRUCTOR + function LogTicks() { + } + //--------------- + // PUBLIC METHODS + function IsSpecified() { + return true; + } + + function SetLabelLogType($aType) { + $this->label_logtype = $aType; + } + + // For log scale it's meaningless to speak about a major step + // We just return -1 to make the framework happy (specifically + // StrokeLabels() ) + function GetMajor() { + return -1; + } + + function SetTextLabelStart($aStart) { + JpGraphError::RaiseL(11005); + //('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.'); + } + + function SetXLabelOffset($dummy) { + // For log scales we dont care about XLabel offset + } + + // Draw ticks on image "img" using scale "scale". The axis absolute + // position in the image is specified in pos, i.e. for an x-axis + // it specifies the absolute y-coord and for Y-ticks it specified the + // absolute x-position. + function Stroke($img,$scale,$pos) { + $start = $scale->GetMinVal(); + $limit = $scale->GetMaxVal(); + $nextMajor = 10*$start; + $step = $nextMajor / 10.0; + + + $img->SetLineWeight($this->weight); + + if( $scale->type == "y" ) { + // member direction specified if the ticks should be on + // left or right side. + $a=$pos + $this->direction*$this->GetMinTickAbsSize(); + $a2=$pos + $this->direction*$this->GetMajTickAbsSize(); + + $count=1; + $this->maj_ticks_pos[0]=$scale->Translate($start); + $this->maj_ticklabels_pos[0]=$scale->Translate($start); + if( $this->supress_first ) + $this->maj_ticks_label[0]=""; + else { + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[0]=call_user_func($f,$start); + } + elseif( $this->label_logtype == LOGLABELS_PLAIN ) { + $this->maj_ticks_label[0]=$start; + } + else { + $this->maj_ticks_label[0]='10^'.round(log10($start)); + } + } + $i=1; + for($y=$start; $y<=$limit; $y+=$step,++$count ) { + $ys=$scale->Translate($y); + $this->ticks_pos[]=$ys; + $this->ticklabels_pos[]=$ys; + if( $count % 10 == 0 ) { + if( !$this->supress_tickmarks ) { + if( $this->majcolor!="" ) { + $img->PushColor($this->majcolor); + $img->Line($pos,$ys,$a2,$ys); + $img->PopColor(); + } + else { + $img->Line($pos,$ys,$a2,$ys); + } + } + + $this->maj_ticks_pos[$i]=$ys; + $this->maj_ticklabels_pos[$i]=$ys; + + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); + } + elseif( $this->label_logtype == 0 ) { + $this->maj_ticks_label[$i]=$nextMajor; + } + else { + $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); + } + ++$i; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor!="" ) { + $img->PushColor($this->mincolor); + } + $img->Line($pos,$ys,$a,$ys); + if( $this->mincolor!="" ) { + $img->PopColor(); + } + } + } + } + } + else { + $a=$pos - $this->direction*$this->GetMinTickAbsSize(); + $a2=$pos - $this->direction*$this->GetMajTickAbsSize(); + $count=1; + $this->maj_ticks_pos[0]=$scale->Translate($start); + $this->maj_ticklabels_pos[0]=$scale->Translate($start); + if( $this->supress_first ) { + $this->maj_ticks_label[0]=""; + } + else { + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[0]=call_user_func($f,$start); + } + elseif( $this->label_logtype == 0 ) { + $this->maj_ticks_label[0]=$start; + } + else { + $this->maj_ticks_label[0]='10^'.round(log10($start)); + } + } + $i=1; + for($x=$start; $x<=$limit; $x+=$step,++$count ) { + $xs=$scale->Translate($x); + $this->ticks_pos[]=$xs; + $this->ticklabels_pos[]=$xs; + if( $count % 10 == 0 ) { + if( !$this->supress_tickmarks ) { + $img->Line($xs,$pos,$xs,$a2); + } + $this->maj_ticks_pos[$i]=$xs; + $this->maj_ticklabels_pos[$i]=$xs; + + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); + } + elseif( $this->label_logtype == 0 ) { + $this->maj_ticks_label[$i]=$nextMajor; + } + else { + $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); + } + ++$i; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + $img->Line($xs,$pos,$xs,$a); + } + } + } + } + return true; + } +} // Class +/* EOF */ +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_meshinterpolate.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_meshinterpolate.inc.php index 68fc5ab..eaee2e7 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_meshinterpolate.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_meshinterpolate.inc.php @@ -1,105 +1,105 @@ -Linear($aData,$aFactor); -} - -/** - * Utility class to interpolate a given data matrix - * - */ -class MeshInterpolate { - private $data = array(); - - /** - * Calculate the mid points of the given rectangle which has its top left - * corner at $row,$col. The $aFactordecides how many spliots should be done. - * i.e. how many more divisions should be done recursively - * - * @param $row Top left corner of square to work with - * @param $col Top left corner of square to work with - * $param $aFactor In how many subsquare should we split this square. A value of 1 indicates that no action - */ - function IntSquare( $aRow, $aCol, $aFactor ) { - if ( $aFactor <= 1 ) - return; - - $step = pow( 2, $aFactor-1 ); - - $v0 = $this->data[$aRow][$aCol]; - $v1 = $this->data[$aRow][$aCol + $step]; - $v2 = $this->data[$aRow + $step][$aCol]; - $v3 = $this->data[$aRow + $step][$aCol + $step]; - - $this->data[$aRow][$aCol + $step / 2] = ( $v0 + $v1 ) / 2; - $this->data[$aRow + $step / 2][$aCol] = ( $v0 + $v2 ) / 2; - $this->data[$aRow + $step][$aCol + $step / 2] = ( $v2 + $v3 ) / 2; - $this->data[$aRow + $step / 2][$aCol + $step] = ( $v1 + $v3 ) / 2; - $this->data[$aRow + $step / 2][$aCol + $step / 2] = ( $v0 + $v1 + $v2 + $v3 ) / 4; - - $this->IntSquare( $aRow, $aCol, $aFactor-1 ); - $this->IntSquare( $aRow, $aCol + $step / 2, $aFactor-1 ); - $this->IntSquare( $aRow + $step / 2, $aCol, $aFactor-1 ); - $this->IntSquare( $aRow + $step / 2, $aCol + $step / 2, $aFactor-1 ); - } - - /** - * Interpolate values in a matrice so that the total number of data points - * in vert and horizontal axis are $aIntNbr more. For example $aIntNbr=2 will - * make the data matrice have tiwce as many vertical and horizontal dta points. - * - * Note: This will blow up the matrcide in memory size in the order of $aInNbr^2 - * - * @param $ &$aData The original data matricde - * @param $aInNbr Interpolation factor - * @return the interpolated matrice - */ - function Linear( &$aData, $aIntFactor ) { - $step = pow( 2, $aIntFactor-1 ); - - $orig_cols = count( $aData[0] ); - $orig_rows = count( $aData ); - // Number of new columns/rows - // N = (a-1) * 2^(f-1) + 1 - $p = pow( 2, $aIntFactor-1 ); - $new_cols = $p * ( $orig_cols - 1 ) + 1; - $new_rows = $p * ( $orig_rows - 1 ) + 1; - - $this->data = array_fill( 0, $new_rows, array_fill( 0, $new_cols, 0 ) ); - // Initialize the new matrix with the values that we know - for ( $i = 0; $i < $new_rows; $i++ ) { - for ( $j = 0; $j < $new_cols; $j++ ) { - $v = 0 ; - if ( ( $i % $step == 0 ) && ( $j % $step == 0 ) ) { - $v = $aData[$i / $step][$j / $step]; - } - $this->data[$i][$j] = $v; - } - } - - for ( $i = 0; $i < $new_rows-1; $i += $step ) { - for ( $j = 0; $j < $new_cols-1; $j += $step ) { - $this->IntSquare( $i, $j, $aIntFactor ); - } - } - - return $this->data; - } -} - -?> +Linear($aData,$aFactor); +} + +/** + * Utility class to interpolate a given data matrix + * + */ +class MeshInterpolate { + private $data = array(); + + /** + * Calculate the mid points of the given rectangle which has its top left + * corner at $row,$col. The $aFactordecides how many spliots should be done. + * i.e. how many more divisions should be done recursively + * + * @param $row Top left corner of square to work with + * @param $col Top left corner of square to work with + * $param $aFactor In how many subsquare should we split this square. A value of 1 indicates that no action + */ + function IntSquare( $aRow, $aCol, $aFactor ) { + if ( $aFactor <= 1 ) + return; + + $step = pow( 2, $aFactor-1 ); + + $v0 = $this->data[$aRow][$aCol]; + $v1 = $this->data[$aRow][$aCol + $step]; + $v2 = $this->data[$aRow + $step][$aCol]; + $v3 = $this->data[$aRow + $step][$aCol + $step]; + + $this->data[$aRow][$aCol + $step / 2] = ( $v0 + $v1 ) / 2; + $this->data[$aRow + $step / 2][$aCol] = ( $v0 + $v2 ) / 2; + $this->data[$aRow + $step][$aCol + $step / 2] = ( $v2 + $v3 ) / 2; + $this->data[$aRow + $step / 2][$aCol + $step] = ( $v1 + $v3 ) / 2; + $this->data[$aRow + $step / 2][$aCol + $step / 2] = ( $v0 + $v1 + $v2 + $v3 ) / 4; + + $this->IntSquare( $aRow, $aCol, $aFactor-1 ); + $this->IntSquare( $aRow, $aCol + $step / 2, $aFactor-1 ); + $this->IntSquare( $aRow + $step / 2, $aCol, $aFactor-1 ); + $this->IntSquare( $aRow + $step / 2, $aCol + $step / 2, $aFactor-1 ); + } + + /** + * Interpolate values in a matrice so that the total number of data points + * in vert and horizontal axis are $aIntNbr more. For example $aIntNbr=2 will + * make the data matrice have tiwce as many vertical and horizontal dta points. + * + * Note: This will blow up the matrcide in memory size in the order of $aInNbr^2 + * + * @param $ &$aData The original data matricde + * @param $aInNbr Interpolation factor + * @return the interpolated matrice + */ + function Linear( &$aData, $aIntFactor ) { + $step = pow( 2, $aIntFactor-1 ); + + $orig_cols = count( $aData[0] ); + $orig_rows = count( $aData ); + // Number of new columns/rows + // N = (a-1) * 2^(f-1) + 1 + $p = pow( 2, $aIntFactor-1 ); + $new_cols = $p * ( $orig_cols - 1 ) + 1; + $new_rows = $p * ( $orig_rows - 1 ) + 1; + + $this->data = array_fill( 0, $new_rows, array_fill( 0, $new_cols, 0 ) ); + // Initialize the new matrix with the values that we know + for ( $i = 0; $i < $new_rows; $i++ ) { + for ( $j = 0; $j < $new_cols; $j++ ) { + $v = 0 ; + if ( ( $i % $step == 0 ) && ( $j % $step == 0 ) ) { + $v = $aData[$i / $step][$j / $step]; + } + $this->data[$i][$j] = $v; + } + } + + for ( $i = 0; $i < $new_rows-1; $i += $step ) { + for ( $j = 0; $j < $new_cols-1; $j += $step ) { + $this->IntSquare( $i, $j, $aIntFactor ); + } + } + + return $this->data; + } +} + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_mgraph.php b/ext/jpgraph-3.0.7/src/jpgraph_mgraph.php index fbd8f5d..2a51121 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_mgraph.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_mgraph.php @@ -1,345 +1,345 @@ -iWidth = $aWidth; - $this->iHeight = $aHeight; - - // If the cached version exist just read it directly from the - // cache, stream it back to browser and exit - if( $aCachedName!='' && READ_CACHE && $aInline ) { - $this->cache = new ImgStreamCache(); - $this->cache->SetTimeOut($aTimeOut); - $image = new Image(); - if( $this->cache->GetAndStream($image,$aCachedName) ) { - exit(); - } - } - $this->inline = $aInline; - $this->cache_name = $aCachedName; - - $this->title = new Text(); - $this->title->ParagraphAlign('center'); - $this->title->SetFont(FF_FONT2,FS_BOLD); - $this->title->SetMargin(3); - $this->title->SetAlign('center'); - - $this->subtitle = new Text(); - $this->subtitle->ParagraphAlign('center'); - $this->subtitle->SetFont(FF_FONT1,FS_BOLD); - $this->subtitle->SetMargin(3); - $this->subtitle->SetAlign('center'); - - $this->subsubtitle = new Text(); - $this->subsubtitle->ParagraphAlign('center'); - $this->subsubtitle->SetFont(FF_FONT1,FS_NORMAL); - $this->subsubtitle->SetMargin(3); - $this->subsubtitle->SetAlign('center'); - - $this->footer = new Footer(); - - } - - // Specify background fill color for the combined graph - function SetFillColor($aColor) { - $this->iFillColor = $aColor; - } - - // Add a frame around the combined graph - function SetFrame($aFlg,$aColor='black',$aWeight=1) { - $this->iDoFrame = $aFlg; - $this->iFrameColor = $aColor; - $this->iFrameWeight = $aWeight; - } - - // Specify a background image blend - function SetBackgroundImageMix($aMix) { - $this->background_image_mix = $aMix ; - } - - // Specify a background image - function SetBackgroundImage($aFileName,$aCenter_aX=NULL,$aY=NULL) { - // Second argument can be either a boolean value or - // a numeric - $aCenter=TRUE; - $aX=NULL; - - if( is_numeric($aCenter_aX) ) { - $aX=$aCenter_aX; - } - - // Get extension to determine image type - $e = explode('.',$aFileName); - if( !$e ) { - JpGraphError::RaiseL(12002,$aFileName); - //('Incorrect file name for MGraph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); - } - - $valid_formats = array('png', 'jpg', 'gif'); - $aImgFormat = strtolower($e[count($e)-1]); - if ($aImgFormat == 'jpeg') { - $aImgFormat = 'jpg'; - } - elseif (!in_array($aImgFormat, $valid_formats) ) { - JpGraphError::RaiseL(12003,$aImgFormat,$aFileName); - //('Unknown file extension ($aImgFormat) in MGraph::SetBackgroundImage() for filename: '.$aFileName); - } - - $this->background_image = $aFileName; - $this->background_image_center=$aCenter; - $this->background_image_format=$aImgFormat; - $this->background_image_x = $aX; - $this->background_image_y = $aY; - } - - function _strokeBackgroundImage() { - if( $this->background_image == '' ) return; - - $bkgimg = Graph::LoadBkgImage('',$this->background_image); - - // Background width & Heoght - $bw = imagesx($bkgimg); - $bh = imagesy($bkgimg); - - // Canvas width and height - $cw = imagesx($this->img); - $ch = imagesy($this->img); - - if( $this->doshadow ) { - $cw -= $this->shadow_width; - $ch -= $this->shadow_width; - } - - if( $this->background_image_x === NULL || $this->background_image_y === NULL ) { - if( $this->background_image_center ) { - // Center original image in the plot area - $x = round($cw/2-$bw/2); $y = round($ch/2-$bh/2); - } - else { - // Just copy the image from left corner, no resizing - $x=0; $y=0; - } - } - else { - $x = $this->background_image_x; - $y = $this->background_image_y; - } - imagecopymerge($this->img,$bkgimg,$x,$y,0,0,$bw,$bh,$this->background_image_mix); - } - - function AddMix($aGraph,$x=0,$y=0,$mix=100,$fx=0,$fy=0,$w=0,$h=0) { - $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h,$mix); - } - - function Add($aGraph,$x=0,$y=0,$fx=0,$fy=0,$w=0,$h=0) { - $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h); - } - - function _gdImgHandle($agdCanvas,$x,$y,$fx=0,$fy=0,$w=0,$h=0,$mix=100) { - if( $w == 0 ) { - $w = @imagesx($agdCanvas); - } - if( $w === NULL ) { - JpGraphError::RaiseL(12007); - //('Argument to MGraph::Add() is not a valid GD image handle.'); - return; - } - if( $h == 0 ) { - $h = @imagesy($agdCanvas); - } - $this->iGraphs[$this->iCnt++] = array($agdCanvas,$x,$y,$fx,$fy,$w,$h,$mix); - } - - function SetMargin($lm,$rm,$tm,$bm) { - $this->lm = $lm; - $this->rm = $rm; - $this->tm = $tm; - $this->bm = $bm; - } - - function SetExpired($aFlg=true) { - $this->expired = $aFlg; - } - - function SetImgFormat($aFormat,$aQuality=75) { - $this->image_format = $aFormat; - $this->image_quality = $aQuality; - } - - // Set the shadow around the whole image - function SetShadow($aShowShadow=true,$aShadowWidth=4,$aShadowColor='gray@0.3') { - $this->doshadow = $aShowShadow; - $this->shadow_color = $aShadowColor; - $this->shadow_width = $aShadowWidth; - $this->footer->iBottomMargin += $aShadowWidth; - $this->footer->iRightMargin += $aShadowWidth; - } - - function StrokeTitle($image,$w,$h) { - // Stroke title - if( $this->title->t !== '' ) { - - $margin = 3; - - $y = $this->title->margin; - if( $this->title->halign == 'center' ) { - $this->title->Center(0,$w,$y); - } - elseif( $this->title->halign == 'left' ) { - $this->title->SetPos($this->title->margin+2,$y); - } - elseif( $this->title->halign == 'right' ) { - $indent = 0; - if( $this->doshadow ) { - $indent = $this->shadow_width+2; - } - $this->title->SetPos($w-$this->title->margin-$indent,$y,'right'); - } - $this->title->Stroke($image); - - // ... and subtitle - $y += $this->title->GetTextHeight($image) + $margin + $this->subtitle->margin; - if( $this->subtitle->halign == 'center' ) { - $this->subtitle->Center(0,$w,$y); - } - elseif( $this->subtitle->halign == 'left' ) { - $this->subtitle->SetPos($this->subtitle->margin+2,$y); - } - elseif( $this->subtitle->halign == 'right' ) { - $indent = 0; - if( $this->doshadow ) { - $indent = $this->shadow_width+2; - } - $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); - } - $this->subtitle->Stroke($image); - - // ... and subsubtitle - $y += $this->subtitle->GetTextHeight($image) + $margin + $this->subsubtitle->margin; - if( $this->subsubtitle->halign == 'center' ) { - $this->subsubtitle->Center(0,$w,$y); - } - elseif( $this->subsubtitle->halign == 'left' ) { - $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); - } - elseif( $this->subsubtitle->halign == 'right' ) { - $indent = 0; - if( $this->doshadow ) { - $indent = $this->shadow_width+2; - } - $this->subsubtitle->SetPos($w-$this->subsubtitle->margin-$indent,$y,'right'); - } - $this->subsubtitle->Stroke($image); - - } - } - - function Stroke($aFileName='') { - // Find out the necessary size for the container image - $w=0; $h=0; - for($i=0; $i < $this->iCnt; ++$i ) { - $maxw = $this->iGraphs[$i][1]+$this->iGraphs[$i][5]; - $maxh = $this->iGraphs[$i][2]+$this->iGraphs[$i][6]; - $w = max( $w, $maxw ); - $h = max( $h, $maxh ); - } - $w += $this->lm+$this->rm; - $h += $this->tm+$this->bm; - - // User specified width,height overrides - if( $this->iWidth !== NULL && $this->iWidth !== 0 ) $w = $this->iWidth; - if( $this->iHeight!== NULL && $this->iHeight !== 0) $h = $this->iHeight; - - if( $this->doshadow ) { - $w += $this->shadow_width; - $h += $this->shadow_width; - } - - $image = new Image($w,$h); - $image->SetImgFormat( $this->image_format,$this->image_quality); - - if( $this->doshadow ) { - $image->SetColor($this->iFrameColor); - $image->ShadowRectangle(0,0,$w-1,$h-1,$this->iFillColor,$this->shadow_width,$this->shadow_color); - $w -= $this->shadow_width; - $h -= $this->shadow_width; - } - else { - $image->SetColor($this->iFillColor); - $image->FilledRectangle(0,0,$w-1,$h-1); - } - $image->SetExpired($this->expired); - - $this->img = $image->img; - $this->_strokeBackgroundImage(); - - if( $this->iDoFrame && ! $this->doshadow ) { - $image->SetColor($this->iFrameColor); - $image->SetLineWeight($this->iFrameWeight); - $image->Rectangle(0,0,$w-1,$h-1); - } - - // Copy all sub graphs to the container - for($i=0; $i < $this->iCnt; ++$i ) { - $image->CopyMerge($this->iGraphs[$i][0], - $this->iGraphs[$i][1]+$this->lm,$this->iGraphs[$i][2]+$this->tm, - $this->iGraphs[$i][3],$this->iGraphs[$i][4], - $this->iGraphs[$i][5],$this->iGraphs[$i][6], - -1,-1, /* Full from width and height */ - $this->iGraphs[$i][7]); - - - } - - $this->StrokeTitle($image,$w,$h); - $this->footer->Stroke($image); - - // Output image - if( $aFileName == _IMG_HANDLER ) { - return $image->img; - } - else { - //Finally stream the generated picture - $this->cache = new ImgStreamCache(); - $this->cache->PutAndStream($image,$this->cache_name,$this->inline,$aFileName); - } - } -} - -// EOF - -?> +iWidth = $aWidth; + $this->iHeight = $aHeight; + + // If the cached version exist just read it directly from the + // cache, stream it back to browser and exit + if( $aCachedName!='' && READ_CACHE && $aInline ) { + $this->cache = new ImgStreamCache(); + $this->cache->SetTimeOut($aTimeOut); + $image = new Image(); + if( $this->cache->GetAndStream($image,$aCachedName) ) { + exit(); + } + } + $this->inline = $aInline; + $this->cache_name = $aCachedName; + + $this->title = new Text(); + $this->title->ParagraphAlign('center'); + $this->title->SetFont(FF_FONT2,FS_BOLD); + $this->title->SetMargin(3); + $this->title->SetAlign('center'); + + $this->subtitle = new Text(); + $this->subtitle->ParagraphAlign('center'); + $this->subtitle->SetFont(FF_FONT1,FS_BOLD); + $this->subtitle->SetMargin(3); + $this->subtitle->SetAlign('center'); + + $this->subsubtitle = new Text(); + $this->subsubtitle->ParagraphAlign('center'); + $this->subsubtitle->SetFont(FF_FONT1,FS_NORMAL); + $this->subsubtitle->SetMargin(3); + $this->subsubtitle->SetAlign('center'); + + $this->footer = new Footer(); + + } + + // Specify background fill color for the combined graph + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + // Add a frame around the combined graph + function SetFrame($aFlg,$aColor='black',$aWeight=1) { + $this->iDoFrame = $aFlg; + $this->iFrameColor = $aColor; + $this->iFrameWeight = $aWeight; + } + + // Specify a background image blend + function SetBackgroundImageMix($aMix) { + $this->background_image_mix = $aMix ; + } + + // Specify a background image + function SetBackgroundImage($aFileName,$aCenter_aX=NULL,$aY=NULL) { + // Second argument can be either a boolean value or + // a numeric + $aCenter=TRUE; + $aX=NULL; + + if( is_numeric($aCenter_aX) ) { + $aX=$aCenter_aX; + } + + // Get extension to determine image type + $e = explode('.',$aFileName); + if( !$e ) { + JpGraphError::RaiseL(12002,$aFileName); + //('Incorrect file name for MGraph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); + } + + $valid_formats = array('png', 'jpg', 'gif'); + $aImgFormat = strtolower($e[count($e)-1]); + if ($aImgFormat == 'jpeg') { + $aImgFormat = 'jpg'; + } + elseif (!in_array($aImgFormat, $valid_formats) ) { + JpGraphError::RaiseL(12003,$aImgFormat,$aFileName); + //('Unknown file extension ($aImgFormat) in MGraph::SetBackgroundImage() for filename: '.$aFileName); + } + + $this->background_image = $aFileName; + $this->background_image_center=$aCenter; + $this->background_image_format=$aImgFormat; + $this->background_image_x = $aX; + $this->background_image_y = $aY; + } + + function _strokeBackgroundImage() { + if( $this->background_image == '' ) return; + + $bkgimg = Graph::LoadBkgImage('',$this->background_image); + + // Background width & Heoght + $bw = imagesx($bkgimg); + $bh = imagesy($bkgimg); + + // Canvas width and height + $cw = imagesx($this->img); + $ch = imagesy($this->img); + + if( $this->doshadow ) { + $cw -= $this->shadow_width; + $ch -= $this->shadow_width; + } + + if( $this->background_image_x === NULL || $this->background_image_y === NULL ) { + if( $this->background_image_center ) { + // Center original image in the plot area + $x = round($cw/2-$bw/2); $y = round($ch/2-$bh/2); + } + else { + // Just copy the image from left corner, no resizing + $x=0; $y=0; + } + } + else { + $x = $this->background_image_x; + $y = $this->background_image_y; + } + imagecopymerge($this->img,$bkgimg,$x,$y,0,0,$bw,$bh,$this->background_image_mix); + } + + function AddMix($aGraph,$x=0,$y=0,$mix=100,$fx=0,$fy=0,$w=0,$h=0) { + $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h,$mix); + } + + function Add($aGraph,$x=0,$y=0,$fx=0,$fy=0,$w=0,$h=0) { + $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h); + } + + function _gdImgHandle($agdCanvas,$x,$y,$fx=0,$fy=0,$w=0,$h=0,$mix=100) { + if( $w == 0 ) { + $w = @imagesx($agdCanvas); + } + if( $w === NULL ) { + JpGraphError::RaiseL(12007); + //('Argument to MGraph::Add() is not a valid GD image handle.'); + return; + } + if( $h == 0 ) { + $h = @imagesy($agdCanvas); + } + $this->iGraphs[$this->iCnt++] = array($agdCanvas,$x,$y,$fx,$fy,$w,$h,$mix); + } + + function SetMargin($lm,$rm,$tm,$bm) { + $this->lm = $lm; + $this->rm = $rm; + $this->tm = $tm; + $this->bm = $bm; + } + + function SetExpired($aFlg=true) { + $this->expired = $aFlg; + } + + function SetImgFormat($aFormat,$aQuality=75) { + $this->image_format = $aFormat; + $this->image_quality = $aQuality; + } + + // Set the shadow around the whole image + function SetShadow($aShowShadow=true,$aShadowWidth=4,$aShadowColor='gray@0.3') { + $this->doshadow = $aShowShadow; + $this->shadow_color = $aShadowColor; + $this->shadow_width = $aShadowWidth; + $this->footer->iBottomMargin += $aShadowWidth; + $this->footer->iRightMargin += $aShadowWidth; + } + + function StrokeTitle($image,$w,$h) { + // Stroke title + if( $this->title->t !== '' ) { + + $margin = 3; + + $y = $this->title->margin; + if( $this->title->halign == 'center' ) { + $this->title->Center(0,$w,$y); + } + elseif( $this->title->halign == 'left' ) { + $this->title->SetPos($this->title->margin+2,$y); + } + elseif( $this->title->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->title->SetPos($w-$this->title->margin-$indent,$y,'right'); + } + $this->title->Stroke($image); + + // ... and subtitle + $y += $this->title->GetTextHeight($image) + $margin + $this->subtitle->margin; + if( $this->subtitle->halign == 'center' ) { + $this->subtitle->Center(0,$w,$y); + } + elseif( $this->subtitle->halign == 'left' ) { + $this->subtitle->SetPos($this->subtitle->margin+2,$y); + } + elseif( $this->subtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); + } + $this->subtitle->Stroke($image); + + // ... and subsubtitle + $y += $this->subtitle->GetTextHeight($image) + $margin + $this->subsubtitle->margin; + if( $this->subsubtitle->halign == 'center' ) { + $this->subsubtitle->Center(0,$w,$y); + } + elseif( $this->subsubtitle->halign == 'left' ) { + $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); + } + elseif( $this->subsubtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) { + $indent = $this->shadow_width+2; + } + $this->subsubtitle->SetPos($w-$this->subsubtitle->margin-$indent,$y,'right'); + } + $this->subsubtitle->Stroke($image); + + } + } + + function Stroke($aFileName='') { + // Find out the necessary size for the container image + $w=0; $h=0; + for($i=0; $i < $this->iCnt; ++$i ) { + $maxw = $this->iGraphs[$i][1]+$this->iGraphs[$i][5]; + $maxh = $this->iGraphs[$i][2]+$this->iGraphs[$i][6]; + $w = max( $w, $maxw ); + $h = max( $h, $maxh ); + } + $w += $this->lm+$this->rm; + $h += $this->tm+$this->bm; + + // User specified width,height overrides + if( $this->iWidth !== NULL && $this->iWidth !== 0 ) $w = $this->iWidth; + if( $this->iHeight!== NULL && $this->iHeight !== 0) $h = $this->iHeight; + + if( $this->doshadow ) { + $w += $this->shadow_width; + $h += $this->shadow_width; + } + + $image = new Image($w,$h); + $image->SetImgFormat( $this->image_format,$this->image_quality); + + if( $this->doshadow ) { + $image->SetColor($this->iFrameColor); + $image->ShadowRectangle(0,0,$w-1,$h-1,$this->iFillColor,$this->shadow_width,$this->shadow_color); + $w -= $this->shadow_width; + $h -= $this->shadow_width; + } + else { + $image->SetColor($this->iFillColor); + $image->FilledRectangle(0,0,$w-1,$h-1); + } + $image->SetExpired($this->expired); + + $this->img = $image->img; + $this->_strokeBackgroundImage(); + + if( $this->iDoFrame && ! $this->doshadow ) { + $image->SetColor($this->iFrameColor); + $image->SetLineWeight($this->iFrameWeight); + $image->Rectangle(0,0,$w-1,$h-1); + } + + // Copy all sub graphs to the container + for($i=0; $i < $this->iCnt; ++$i ) { + $image->CopyMerge($this->iGraphs[$i][0], + $this->iGraphs[$i][1]+$this->lm,$this->iGraphs[$i][2]+$this->tm, + $this->iGraphs[$i][3],$this->iGraphs[$i][4], + $this->iGraphs[$i][5],$this->iGraphs[$i][6], + -1,-1, /* Full from width and height */ + $this->iGraphs[$i][7]); + + + } + + $this->StrokeTitle($image,$w,$h); + $this->footer->Stroke($image); + + // Output image + if( $aFileName == _IMG_HANDLER ) { + return $image->img; + } + else { + //Finally stream the generated picture + $this->cache = new ImgStreamCache(); + $this->cache->PutAndStream($image,$this->cache_name,$this->inline,$aFileName); + } + } +} + +// EOF + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_pie.php b/ext/jpgraph-3.0.7/src/jpgraph_pie.php index c2dd65a..08dbc10 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_pie.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_pie.php @@ -1,1462 +1,1462 @@ - array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430), - "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38), - "water" => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388), - "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393)); - protected $theme="earth"; - protected $setslicecolors=array(); - protected $labeltype=0; // Default to percentage - protected $pie_border=true,$pie_interior_border=true; - public $value; - protected $ishadowcolor='',$ishadowdrop=4; - protected $ilabelposadj=1; - protected $legendcsimtargets = array(),$legendcsimwintargets = array(); - protected $legendcsimalts = array(); - protected $adjusted_data = array(); - public $guideline = null; - protected $guidelinemargin=10,$iShowGuideLineForSingle = false; - protected $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8; - protected $la = array(); // Holds the exact angle for each label - - //--------------- - // CONSTRUCTOR - function __construct($data) { - $this->data = array_reverse($data); - $this->title = new Text(""); - $this->title->SetFont(FF_FONT1,FS_BOLD); - $this->value = new DisplayValue(); - $this->value->Show(); - $this->value->SetFormat('%.1f%%'); - $this->guideline = new LineProperty(); - } - - //--------------- - // PUBLIC METHODS - function SetCenter($x,$y=0.5) { - $this->posx = $x; - $this->posy = $y; - } - - // Enable guideline and set drwaing policy - function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) { - $this->guideline->Show($aFlg); - $this->iShowGuideLineForSingle = $aAlways; - $this->iGuideLineCurve = $aCurved; - } - - // Adjuste the distance between labels and labels and pie - function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) { - $this->iGuideVFactor=$aVFactor; - $this->iGuideLineRFactor=$aRFactor; - } - - function SetColor($aColor) { - $this->color = $aColor; - } - - function SetSliceColors($aColors) { - $this->setslicecolors = $aColors; - } - - function SetShadow($aColor='darkgray',$aDropWidth=4) { - $this->ishadowcolor = $aColor; - $this->ishadowdrop = $aDropWidth; - } - - function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { - $this->csimtargets=array_reverse($aTargets); - if( is_array($aWinTargets) ) - $this->csimwintargets=array_reverse($aWinTargets); - if( is_array($aAlts) ) - $this->csimalts=array_reverse($aAlts); - } - - function GetCSIMareas() { - return $this->csimareas; - } - - function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { - //Slice number, ellipse centre (x,y), height, width, start angle, end angle - while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; - while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; - - $sa = 2*M_PI - $sa; - $ea = 2*M_PI - $ea; - - // Special case when we have only one slice since then both start and end - // angle will be == 0 - if( abs($sa - $ea) < 0.0001 ) { - $sa=2*M_PI; $ea=0; - } - - //add coordinates of the centre to the map - $xc = floor($xc);$yc=floor($yc); - $coords = "$xc, $yc"; - - //add coordinates of the first point on the arc to the map - $xp = floor(($radius*cos($ea))+$xc); - $yp = floor($yc-$radius*sin($ea)); - $coords.= ", $xp, $yp"; - - //add coordinates every 0.2 radians - $a=$ea+0.2; - - // If we cross the 360-limit with a slice we need to handle - // the fact that end angle is smaller than start - if( $sa < $ea ) { - while ($a <= 2*M_PI) { - $xp = floor($radius*cos($a)+$xc); - $yp = floor($yc-$radius*sin($a)); - $coords.= ", $xp, $yp"; - $a += 0.2; - } - $a -= 2*M_PI; - } - - - while ($a < $sa) { - $xp = floor($radius*cos($a)+$xc); - $yp = floor($yc-$radius*sin($a)); - $coords.= ", $xp, $yp"; - $a += 0.2; - } - - //Add the last point on the arc - $xp = floor($radius*cos($sa)+$xc); - $yp = floor($yc-$radius*sin($sa)); - $coords.= ", $xp, $yp"; - if( !empty($this->csimtargets[$i]) ) { - $this->csimareas .= "csimtargets[$i]."\""; - $tmp=""; - if( !empty($this->csimwintargets[$i]) ) { - $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; - } - if( !empty($this->csimalts[$i]) ) { - $tmp=sprintf($this->csimalts[$i],$this->data[$i]); - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - } - - - function SetTheme($aTheme) { - if( in_array($aTheme,array_keys($this->themearr)) ) - $this->theme = $aTheme; - else - JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme"); - } - - function ExplodeSlice($e,$radius=20) { - if( ! is_integer($e) ) - JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer'); - $this->explode_radius[$e]=$radius; - } - - function ExplodeAll($radius=20) { - $this->explode_all=true; - $this->explode_r = $radius; - } - - function Explode($aExplodeArr) { - if( !is_array($aExplodeArr) ) { - JpGraphError::RaiseL(15003); - //("Argument to PiePlot::Explode() must be an array with integer distances."); - } - $this->explode_radius = $aExplodeArr; - } - - function SetStartAngle($aStart) { - if( $aStart < 0 || $aStart > 360 ) { - JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.'); - } - if( $aStart == 0 ) { - $this->startangle = 0; - } - else { - $this->startangle = 360-$aStart; - $this->startangle *= M_PI/180; - } - } - - // Size in percentage - function SetSize($aSize) { - if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) ) - $this->radius = $aSize; - else - JpGraphError::RaiseL(15006); - //("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]"); - } - - // Set label arrays - function SetLegends($aLegend) { - $this->legends = $aLegend; - } - - // Set text labels for slices - function SetLabels($aLabels,$aLblPosAdj="auto") { - $this->labels = array_reverse($aLabels); - $this->ilabelposadj=$aLblPosAdj; - } - - function SetLabelPos($aLblPosAdj) { - $this->ilabelposadj=$aLblPosAdj; - } - - // Should we display actual value or percentage? - function SetLabelType($aType) { - if( $aType < 0 || $aType > 2 ) - JpGraphError::RaiseL(15008,$aType); - //("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t)."); - $this->labeltype = $aType; - } - - // Deprecated. - function SetValueType($aType) { - $this->SetLabelType($aType); - } - - // Should the circle around a pie plot be displayed - function ShowBorder($exterior=true,$interior=true) { - $this->pie_border = $exterior; - $this->pie_interior_border = $interior; - } - - // Setup the legends - function Legend($graph) { - $colors = array_keys($graph->img->rgb->rgb_table); - sort($colors); - $ta=$this->themearr[$this->theme]; - $n = count($this->data); - - if( $this->setslicecolors==null ) { - $numcolors=count($ta); - if( class_exists('PiePlot3D',false) && ($this instanceof PiePlot3D) ) { - $ta = array_reverse(array_slice($ta,0,$n)); - } - } - else { - $this->setslicecolors = array_slice($this->setslicecolors,0,$n); - $numcolors=count($this->setslicecolors); - if( $graph->pieaa && !($this instanceof PiePlot3D) ) { - $this->setslicecolors = array_reverse($this->setslicecolors); - } - } - - $sum=0; - for($i=0; $i < $n; ++$i) - $sum += $this->data[$i]; - - // Bail out with error if the sum is 0 - if( $sum==0 ) - JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!"); - - // Make sure we don't plot more values than data points - // (in case the user added more legends than data points) - $n = min(count($this->legends),count($this->data)); - if( $this->legends != "" ) { - $this->legends = array_reverse(array_slice($this->legends,0,$n)); - } - for( $i=$n-1; $i >= 0; --$i ) { - $l = $this->legends[$i]; - // Replace possible format with actual values - if( count($this->csimalts) > $i ) { - $fmt = $this->csimalts[$i]; - } - else { - $fmt = "%d"; // Deafult Alt if no other has been specified - } - if( $this->labeltype==0 ) { - $l = sprintf($l,100*$this->data[$i]/$sum); - $alt = sprintf($fmt,$this->data[$i]); - - } - elseif( $this->labeltype == 1) { - $l = sprintf($l,$this->data[$i]); - $alt = sprintf($fmt,$this->data[$i]); - - } - else { - $l = sprintf($l,$this->adjusted_data[$i]); - $alt = sprintf($fmt,$this->adjusted_data[$i]); - } - - if( empty($this->csimwintargets[$i]) ) { - $wintarg = ''; - } - else { - $wintarg = $this->csimwintargets[$i]; - } - - if( $this->setslicecolors==null ) { - $graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt,$wintarg); - } - else { - $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt,$wintarg); - } - } - } - - // Adjust the rounded percetage value so that the sum of - // of the pie slices are always 100% - // Using the Hare/Niemeyer method - function AdjPercentage($aData,$aPrec=0) { - $mul=100; - if( $aPrec > 0 && $aPrec < 3 ) { - if( $aPrec == 1 ) - $mul=1000; - else - $mul=10000; - } - - $tmp = array(); - $result = array(); - $quote_sum=0; - $n = count($aData) ; - for( $i=0, $sum=0; $i < $n; ++$i ) - $sum+=$aData[$i]; - foreach($aData as $index => $value) { - $tmp_percentage=$value/$sum*$mul; - $result[$index]=floor($tmp_percentage); - $tmp[$index]=$tmp_percentage-$result[$index]; - $quote_sum+=$result[$index]; - } - if( $quote_sum == $mul) { - if( $mul > 100 ) { - $tmp = $mul / 100; - for( $i=0; $i < $n; ++$i ) { - $result[$i] /= $tmp ; - } - } - return $result; - } - arsort($tmp,SORT_NUMERIC); - reset($tmp); - for($i=0; $i < $mul-$quote_sum; $i++) - { - $result[key($tmp)]++; - next($tmp); - } - if( $mul > 100 ) { - $tmp = $mul / 100; - for( $i=0; $i < $n; ++$i ) { - $result[$i] /= $tmp ; - } - } - return $result; - } - - - function Stroke($img,$aaoption=0) { - // aaoption is used to handle antialias - // aaoption == 0 a normal pie - // aaoption == 1 just the body - // aaoption == 2 just the values - - // Explode scaling. If anti alias we scale the image - // twice and we also need to scale the exploding distance - $expscale = $aaoption === 1 ? 2 : 1; - - if( $this->labeltype == 2 ) { - // Adjust the data so that it will add up to 100% - $this->adjusted_data = $this->AdjPercentage($this->data); - } - - $colors = array_keys($img->rgb->rgb_table); - sort($colors); - $ta=$this->themearr[$this->theme]; - $n = count($this->data); - - if( $this->setslicecolors==null ) { - $numcolors=count($ta); - } - else { - // We need to create an array of colors as long as the data - // since we need to reverse it to get the colors in the right order - $numcolors=count($this->setslicecolors); - $i = 2*$numcolors; - while( $n > $i ) { - $this->setslicecolors = array_merge($this->setslicecolors,$this->setslicecolors); - $i += $n; - } - $tt = array_slice($this->setslicecolors,0,$n % $numcolors); - $this->setslicecolors = array_merge($this->setslicecolors,$tt); - $this->setslicecolors = array_reverse($this->setslicecolors); - } - - // Draw the slices - $sum=0; - for($i=0; $i < $n; ++$i) - $sum += $this->data[$i]; - - // Bail out with error if the sum is 0 - if( $sum==0 ) { - JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie."); - } - - // Set up the pie-circle - if( $this->radius <= 1 ) { - $radius = floor($this->radius*min($img->width,$img->height)); - } - else { - $radius = $aaoption === 1 ? $this->radius*2 : $this->radius; - } - - if( $this->posx <= 1 && $this->posx > 0 ) { - $xc = round($this->posx*$img->width); - } - else { - $xc = $this->posx ; - } - - if( $this->posy <= 1 && $this->posy > 0 ) { - $yc = round($this->posy*$img->height); - } - else { - $yc = $this->posy ; - } - - $n = count($this->data); - - if( $this->explode_all ) { - for($i=0; $i < $n; ++$i) { - $this->explode_radius[$i]=$this->explode_r; - } - } - - // If we have a shadow and not just drawing the labels - if( $this->ishadowcolor != "" && $aaoption !== 2) { - $accsum=0; - $angle2 = $this->startangle; - $img->SetColor($this->ishadowcolor); - for($i=0; $sum > 0 && $i < $n; ++$i) { - $j = $n-$i-1; - $d = $this->data[$i]; - $angle1 = $angle2; - $accsum += $d; - $angle2 = $this->startangle+2*M_PI*$accsum/$sum; - if( empty($this->explode_radius[$j]) ) { - $this->explode_radius[$j]=0; - } - - if( $d < 0.00001 ) continue; - - $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); - - $xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale; - $ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale; - - $xcm += $this->ishadowdrop*$expscale; - $ycm += $this->ishadowdrop*$expscale; - - $_sa = round($angle1*180/M_PI); - $_ea = round($angle2*180/M_PI); - - // The CakeSlice method draws a full circle in case of start angle = end angle - // for pie slices we don't want this behaviour unless we only have one - // slice in the pie in case it is the wanted behaviour - if( $_ea-$_sa > 0.1 || $n==1 ) { - $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1, - $angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor); - } - } - } - - //-------------------------------------------------------------------------------- - // This is the main loop to draw each cake slice - //-------------------------------------------------------------------------------- - - // Set up the accumulated sum, start angle for first slice and border color - $accsum=0; - $angle2 = $this->startangle; - $img->SetColor($this->color); - - // Loop though all the slices if there is a pie to draw (sum>0) - // There are n slices in total - for($i=0; $sum>0 && $i < $n; ++$i) { - - // $j is the actual index used for the slice - $j = $n-$i-1; - - // Make sure we havea valid distance to explode the slice - if( empty($this->explode_radius[$j]) ) { - $this->explode_radius[$j]=0; - } - - // The actual numeric value for the slice - $d = $this->data[$i]; - - $angle1 = $angle2; - - // Accumlate the sum - $accsum += $d; - - // The new angle when we add the "size" of this slice - // angle1 is then the start and angle2 the end of this slice - $angle2 = $this->NormAngle($this->startangle+2*M_PI*$accsum/$sum); - - // We avoid some trouble by not allowing end angle to be 0, in that case - // we translate to 360 - - // la is used to hold the label angle, which is centered on the slice - if( $angle2 < 0.0001 && $angle1 > 0.0001 ) { - $this->la[$i] = 2*M_PI - (abs(2*M_PI-$angle1)/2.0+$angle1); - } - elseif( $angle1 > $angle2 ) { - // The case where the slice crosses the 3 a'clock line - // Remember that the slices are counted clockwise and - // labels are counted counter clockwise so we need to revert with 2 PI - $this->la[$i] = 2*M_PI-$this->NormAngle($angle1 + ((2*M_PI - $angle1)+$angle2)/2); - } - else { - $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); - } - - // Too avoid rounding problems we skip the slice if it is too small - if( $d < 0.00001 ) continue; - - // If the user has specified an array of colors for each slice then use - // that a color otherwise use the theme array (ta) of colors - if( $this->setslicecolors==null ) { - $slicecolor=$colors[$ta[$i%$numcolors]]; - } - else { - $slicecolor=$this->setslicecolors[$i%$numcolors]; - } - -// $_sa = round($angle1*180/M_PI); -// $_ea = round($angle2*180/M_PI); -// $_la = round($this->la[$i]*180/M_PI); -// echo "Slice#$i: ang1=$_sa , ang2=$_ea, la=$_la, color=$slicecolor
      "; - - - // If we have enabled antialias then we don't draw any border so - // make the bordedr color the same as the slice color - if( $this->pie_interior_border && $aaoption===0 ) { - $img->SetColor($this->color); - } - else { - $img->SetColor($slicecolor); - } - $arccolor = $this->pie_border && $aaoption===0 ? $this->color : ""; - - // Calculate the x,y coordinates for the base of this slice taking - // the exploded distance into account. Here we use the mid angle as the - // ray of extension and we have the mid angle handy as it is also the - // label angle - $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale; - $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale; - - // If we are not just drawing the labels then draw this cake slice - if( $aaoption !== 2 ) { - - $_sa = round($angle1*180/M_PI); - $_ea = round($angle2*180/M_PI); - $_la = round($this->la[$i]*180/M_PI); - //echo "[$i] sa=$_sa, ea=$_ea, la[$i]=$_la, (color=$slicecolor)
      "; - - // The CakeSlice method draws a full circle in case of start angle = end angle - // for pie slices we want this in case the slice have a value larger than 99% of the - // total sum - if( abs($_ea-$_sa) >= 1 || $d == $sum ) { - $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,$_sa,$_ea,$slicecolor,$arccolor); - } - } - - // If the CSIM is used then make sure we register a CSIM area for this slice as well - if( $this->csimtargets && $aaoption !== 1 ) { - $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2); - } - } - - // Format the titles for each slice - if( $aaoption !== 2 ) { - for( $i=0; $i < $n; ++$i) { - if( $this->labeltype==0 ) { - if( $sum != 0 ) - $l = 100.0*$this->data[$i]/$sum; - else - $l = 0.0; - } - elseif( $this->labeltype==1 ) { - $l = $this->data[$i]*1.0; - } - else { - $l = $this->adjusted_data[$i]; - } - if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) - $this->labels[$i]=sprintf($this->labels[$i],$l); - else - $this->labels[$i]=$l; - } - } - - if( $this->value->show && $aaoption !== 1 ) { - $this->StrokeAllLabels($img,$xc,$yc,$radius); - } - - // Adjust title position - if( $aaoption !== 1 ) { - $this->title->SetPos($xc, - $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin, - "center","bottom"); - $this->title->Stroke($img); - } - - } - - //--------------- - // PRIVATE METHODS - - function NormAngle($a) { - while( $a < 0 ) $a += 2*M_PI; - while( $a > 2*M_PI ) $a -= 2*M_PI; - return $a; - } - - function Quadrant($a) { - $a=$this->NormAngle($a); - if( $a > 0 && $a <= M_PI/2 ) - return 0; - if( $a > M_PI/2 && $a <= M_PI ) - return 1; - if( $a > M_PI && $a <= 1.5*M_PI ) - return 2; - if( $a > 1.5*M_PI ) - return 3; - } - - function StrokeGuideLabels($img,$xc,$yc,$radius) { - $n = count($this->labels); - - //----------------------------------------------------------------------- - // Step 1 of the algorithm is to construct a number of clusters - // a cluster is defined as all slices within the same quadrant (almost) - // that has an angular distance less than the treshold - //----------------------------------------------------------------------- - $tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster - $incluster=false; // flag if we are currently in a cluster or not - $clusters = array(); // array of clusters - $cidx=-1; // running cluster index - - // Go through all the labels and construct a number of clusters - for($i=0; $i < $n-1; ++$i) { - // Calc the angle distance between two consecutive slices - $a1=$this->la[$i]; - $a2=$this->la[$i+1]; - $q1 = $this->Quadrant($a1); - $q2 = $this->Quadrant($a2); - $diff = abs($a1-$a2); - if( $diff < $tresh_hold ) { - if( $incluster ) { - $clusters[$cidx][1]++; - // Each cluster can only cover one quadrant - // Do we cross a quadrant ( and must break the cluster) - if( $q1 != $q2 ) { - // If we cross a quadrant boundary we normally start a - // new cluster. However we need to take the 12'a clock - // and 6'a clock positions into a special consideration. - // Case 1: WE go from q=1 to q=2 if the last slice on - // the cluster for q=1 is close to 12'a clock and the - // first slice in q=0 is small we extend the previous - // cluster - if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) { - if( $i < $n-2 ) { - $a3 = $this->la[$i+2]; - // If there isn't a cluster coming up with the next-next slice - // we extend the previous cluster to cover this slice as well - if( abs($a3-$a2) >= $tresh_hold ) { - $clusters[$cidx][1]++; - $i++; - } - } - } - elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) { - if( $i < $n-2 ) { - $a3 = $this->la[$i+2]; - // If there isn't a cluster coming up with the next-next slice - // we extend the previous cluster to cover this slice as well - if( abs($a3-$a2) >= $tresh_hold ) { - $clusters[$cidx][1]++; - $i++; - } - } - } - - if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) { - $clusters[$cidx][1]++; - $i++; - } - - $incluster = false; - } - } - elseif( $q1 == $q2) { - $incluster = true; - // Now we have a special case for quadrant 0. If we previously - // have a cluster of one in quadrant 0 we just extend that - // cluster. If we don't do this then we risk that the label - // for the cluster of one will cross the guide-line - if( $q1 == 0 && $cidx > -1 && - $clusters[$cidx][1] == 1 && - $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) { - $clusters[$cidx][1]++; - } - else { - $cidx++; - $clusters[$cidx][0] = $i; - $clusters[$cidx][1] = 1; - } - } - else { - // Create a "cluster" of one since we are just crossing - // a quadrant - $cidx++; - $clusters[$cidx][0] = $i; - $clusters[$cidx][1] = 1; - } - } - else { - if( $incluster ) { - // Add the last slice - $clusters[$cidx][1]++; - $incluster = false; - } - else { // Create a "cluster" of one - $cidx++; - $clusters[$cidx][0] = $i; - $clusters[$cidx][1] = 1; - } - } - } - // Handle the very last slice - if( $incluster ) { - $clusters[$cidx][1]++; - } - else { // Create a "cluster" of one - $cidx++; - $clusters[$cidx][0] = $i; - $clusters[$cidx][1] = 1; - } - - /* - if( true ) { - // Debug printout in labels - for( $i=0; $i <= $cidx; ++$i ) { - for( $j=0; $j < $clusters[$i][1]; ++$j ) { - $a = $this->la[$clusters[$i][0]+$j]; - $aa = round($a*180/M_PI); - $q = $this->Quadrant($a); - $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j"; - } - } - } - */ - - //----------------------------------------------------------------------- - // Step 2 of the algorithm is use the clusters and draw the labels - // and guidelines - //----------------------------------------------------------------------- - - // We use the font height as the base factor for how far we need to - // spread the labels in the Y-direction. - $this->value->ApplyFont($img); - $fh = $img->GetFontHeight(); - $origvstep=$fh*$this->iGuideVFactor; - $this->value->SetMargin(0); - - // Number of clusters found - $nc = count($clusters); - - // Walk through all the clusters - for($i=0; $i < $nc; ++$i) { - - // Start angle and number of slices in this cluster - $csize = $clusters[$i][1]; - $a = $this->la[$clusters[$i][0]]; - $q = $this->Quadrant($a); - - // Now set up the start and end conditions to make sure that - // in each cluster we walk through the all the slices starting with the slice - // closest to the equator. Since all slices are numbered clockwise from "3'a clock" - // we have different conditions depending on in which quadrant the slice lies within. - if( $q == 0 ) { - $start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep; - } - elseif( $q == 1 ) { - $start = 0; $idx = $start; $step = 1; $vstep = -$origvstep; - } - elseif( $q == 2 ) { - $start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep; - } - elseif( $q == 3 ) { - $start = 0; $idx = $start; $step = 1; $vstep = $origvstep; - } - - // Walk through all slices within this cluster - for($j=0; $j < $csize; ++$j) { - // Now adjust the position of the labels in each cluster starting - // with the slice that is closest to the equator of the pie - $a = $this->la[$clusters[$i][0]+$idx]; - - // Guide line start in the center of the arc of the slice - $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; - $x = round($r*cos($a)+$xc); - $y = round($yc-$r*sin($a)); - - // The distance from the arc depends on chosen font and the "R-Factor" - $r += $fh*$this->iGuideLineRFactor; - - // Should the labels be placed curved along the pie or in straight columns - // outside the pie? - if( $this->iGuideLineCurve ) - $xt=round($r*cos($a)+$xc); - - // If this is the first slice in the cluster we need some first time - // proessing - if( $idx == $start ) { - if( ! $this->iGuideLineCurve ) - $xt=round($r*cos($a)+$xc); - $yt=round($yc-$r*sin($a)); - - // Some special consideration in case this cluster starts - // in quadrant 1 or 3 very close to the "equator" (< 20 degrees) - // and the previous clusters last slice is within the tolerance. - // In that case we add a font height to this labels Y-position - // so it doesn't collide with - // the slice in the previous cluster - $prevcluster = ($i + ($nc-1) ) % $nc; - $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1; - if( $q == 1 && $a > 160*M_PI/180 ) { - // Get the angle for the previous clusters last slice - $diff = abs($a-$this->la[$previdx]); - if( $diff < $tresh_hold ) { - $yt -= $fh; - } - } - elseif( $q == 3 && $a > 340*M_PI/180 ) { - // We need to subtract 360 to compare angle distance between - // q=0 and q=3 - $diff = abs($a-$this->la[$previdx]-360*M_PI/180); - if( $diff < $tresh_hold ) { - $yt += $fh; - } - } - - } - else { - // The step is at minimum $vstep but if the slices are relatively large - // we make sure that we add at least a step that corresponds to the vertical - // distance between the centers at the arc on the slice - $prev_a = $this->la[$clusters[$i][0]+($idx-$step)]; - $dy = abs($radius*(sin($a)-sin($prev_a))*1.2); - if( $vstep > 0 ) - $yt += max($vstep,$dy); - else - $yt += min($vstep,-$dy); - } - - $label = $this->labels[$clusters[$i][0]+$idx]; - - if( $csize == 1 ) { - // A "meta" cluster with only one slice - $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; - $rr = $r+$img->GetFontHeight()/2; - $xt=round($rr*cos($a)+$xc); - $yt=round($yc-$rr*sin($a)); - $this->StrokeLabel($label,$img,$xc,$yc,$a,$r); - if( $this->iShowGuideLineForSingle ) - $this->guideline->Stroke($img,$x,$y,$xt,$yt); - } - else { - $this->guideline->Stroke($img,$x,$y,$xt,$yt); - if( $q==1 || $q==2 ) { - // Left side of Pie - $this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt); - $lbladj = -$this->guidelinemargin-5; - $this->value->halign = "right"; - $this->value->valign = "center"; - } - else { - // Right side of pie - $this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt); - $lbladj = $this->guidelinemargin+5; - $this->value->halign = "left"; - $this->value->valign = "center"; - } - $this->value->Stroke($img,$label,$xt+$lbladj,$yt); - } - - // Udate idx to point to next slice in the cluster to process - $idx += $step; - } - } - } - - function StrokeAllLabels($img,$xc,$yc,$radius) { - // First normalize all angles for labels - $n = count($this->la); - for($i=0; $i < $n; ++$i) { - $this->la[$i] = $this->NormAngle($this->la[$i]); - } - if( $this->guideline->iShow ) { - $this->StrokeGuideLabels($img,$xc,$yc,$radius); - } - else { - $n = count($this->labels); - for($i=0; $i < $n; ++$i) { - $this->StrokeLabel($this->labels[$i],$img,$xc,$yc, - $this->la[$i], - $radius + $this->explode_radius[$n-1-$i]); - } - } - } - - // Position the labels of each slice - function StrokeLabel($label,$img,$xc,$yc,$a,$r) { - - // Default value - if( $this->ilabelposadj === 'auto' ) - $this->ilabelposadj = 0.65; - - // We position the values diferently depending on if they are inside - // or outside the pie - if( $this->ilabelposadj < 1.0 ) { - - $this->value->SetAlign('center','center'); - $this->value->margin = 0; - - $xt=round($this->ilabelposadj*$r*cos($a)+$xc); - $yt=round($yc-$this->ilabelposadj*$r*sin($a)); - - $this->value->Stroke($img,$label,$xt,$yt); - } - else { - - $this->value->halign = "left"; - $this->value->valign = "top"; - $this->value->margin = 0; - - // Position the axis title. - // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text - // that intersects with the extension of the corresponding axis. The code looks a little - // bit messy but this is really the only way of having a reasonable position of the - // axis titles. - $this->value->ApplyFont($img); - $h=$img->GetTextHeight($label); - // For numeric values the format of the display value - // must be taken into account - if( is_numeric($label) ) { - if( $label > 0 ) - $w=$img->GetTextWidth(sprintf($this->value->format,$label)); - else - $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); - } - else - $w=$img->GetTextWidth($label); - - if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) { - $r *= $this->ilabelposadj; - } - - $r += $img->GetFontHeight()/1.5; - - $xt=round($r*cos($a)+$xc); - $yt=round($yc-$r*sin($a)); - - // Normalize angle - while( $a < 0 ) $a += 2*M_PI; - while( $a > 2*M_PI ) $a -= 2*M_PI; - - if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; - if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; - if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; - if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); - - if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; - if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); - if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; - if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); - if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; - - $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h); - } - } -} // Class - - -//=================================================== -// CLASS PiePlotC -// Description: Same as a normal pie plot but with a -// filled circle in the center -//=================================================== -class PiePlotC extends PiePlot { - private $imidsize=0.5; // Fraction of total width - private $imidcolor='white'; - public $midtitle=''; - private $middlecsimtarget='',$middlecsimwintarget='',$middlecsimalt=''; - - function __construct($data,$aCenterTitle='') { - parent::__construct($data); - $this->midtitle = new Text(); - $this->midtitle->ParagraphAlign('center'); - } - - function SetMid($aTitle,$aColor='white',$aSize=0.5) { - $this->midtitle->Set($aTitle); - - $this->imidsize = $aSize ; - $this->imidcolor = $aColor ; - } - - function SetMidTitle($aTitle) { - $this->midtitle->Set($aTitle); - } - - function SetMidSize($aSize) { - $this->imidsize = $aSize ; - } - - function SetMidColor($aColor) { - $this->imidcolor = $aColor ; - } - - function SetMidCSIM($aTarget,$aAlt='',$aWinTarget='') { - $this->middlecsimtarget = $aTarget; - $this->middlecsimwintarget = $aWinTarget; - $this->middlecsimalt = $aAlt; - } - - function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { - //Slice number, ellipse centre (x,y), radius, start angle, end angle - while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; - while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; - - $sa = 2*M_PI - $sa; - $ea = 2*M_PI - $ea; - - // Special case when we have only one slice since then both start and end - // angle will be == 0 - if( abs($sa - $ea) < 0.0001 ) { - $sa=2*M_PI; $ea=0; - } - - // Add inner circle first point - $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); - $yp = floor($yc-($this->imidsize*$radius*sin($ea))); - $coords = "$xp, $yp"; - - //add coordinates every 0.25 radians - $a=$ea+0.25; - - // If we cross the 360-limit with a slice we need to handle - // the fact that end angle is smaller than start - if( $sa < $ea ) { - while ($a <= 2*M_PI) { - $xp = floor($radius*cos($a)+$xc); - $yp = floor($yc-$radius*sin($a)); - $coords.= ", $xp, $yp"; - $a += 0.25; - } - $a -= 2*M_PI; - } - - while ($a < $sa) { - $xp = floor(($this->imidsize*$radius*cos($a)+$xc)); - $yp = floor($yc-($this->imidsize*$radius*sin($a))); - $coords.= ", $xp, $yp"; - $a += 0.25; - } - - // Make sure we end at the last point - $xp = floor(($this->imidsize*$radius*cos($sa)+$xc)); - $yp = floor($yc-($this->imidsize*$radius*sin($sa))); - $coords.= ", $xp, $yp"; - - // Straight line to outer circle - $xp = floor($radius*cos($sa)+$xc); - $yp = floor($yc-$radius*sin($sa)); - $coords.= ", $xp, $yp"; - - //add coordinates every 0.25 radians - $a=$sa - 0.25; - while ($a > $ea) { - $xp = floor($radius*cos($a)+$xc); - $yp = floor($yc-$radius*sin($a)); - $coords.= ", $xp, $yp"; - $a -= 0.25; - } - - //Add the last point on the arc - $xp = floor($radius*cos($ea)+$xc); - $yp = floor($yc-$radius*sin($ea)); - $coords.= ", $xp, $yp"; - - // Close the arc - $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); - $yp = floor($yc-($this->imidsize*$radius*sin($ea))); - $coords .= ", $xp, $yp"; - - if( !empty($this->csimtargets[$i]) ) { - $this->csimareas .= "csimtargets[$i]."\""; - if( !empty($this->csimwintargets[$i]) ) { - $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; - } - if( !empty($this->csimalts[$i]) ) { - $tmp=sprintf($this->csimalts[$i],$this->data[$i]); - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - } - - - function Stroke($img,$aaoption=0) { - - // Stroke the pie but don't stroke values - $tmp = $this->value->show; - $this->value->show = false; - parent::Stroke($img,$aaoption); - $this->value->show = $tmp; - - $xc = round($this->posx*$img->width); - $yc = round($this->posy*$img->height); - - $radius = floor($this->radius * min($img->width,$img->height)) ; - - - if( $this->imidsize > 0 && $aaoption !== 2 ) { - - if( $this->ishadowcolor != "" ) { - $img->SetColor($this->ishadowcolor); - $img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop, - round($radius*$this->imidsize)); - } - - $img->SetColor($this->imidcolor); - $img->FilledCircle($xc,$yc,round($radius*$this->imidsize)); - - if( $this->pie_border && $aaoption === 0 ) { - $img->SetColor($this->color); - $img->Circle($xc,$yc,round($radius*$this->imidsize)); - } - - if( !empty($this->middlecsimtarget) ) - $this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize)); - - } - - if( $this->value->show && $aaoption !== 1) { - $this->StrokeAllLabels($img,$xc,$yc,$radius); - $this->midtitle->SetPos($xc,$yc,'center','center'); - $this->midtitle->Stroke($img); - } - - } - - function AddMiddleCSIM($xc,$yc,$r) { - $xc=round($xc);$yc=round($yc);$r=round($r); - $this->csimareas .= "middlecsimtarget."\""; - if( !empty($this->middlecsimwintarget) ) { - $this->csimareas .= " target=\"".$this->middlecsimwintarget."\""; - } - if( !empty($this->middlecsimalt) ) { - $tmp = $this->middlecsimalt; - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - - function StrokeLabel($label,$img,$xc,$yc,$a,$r) { - - if( $this->ilabelposadj === 'auto' ) - $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize; - - parent::StrokeLabel($label,$img,$xc,$yc,$a,$r); - - } - -} - - -//=================================================== -// CLASS PieGraph -// Description: -//=================================================== -class PieGraph extends Graph { - private $posx, $posy, $radius; - private $legends=array(); - public $plots=array(); - public $pieaa = false ; - //--------------- - // CONSTRUCTOR - function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { - parent::__construct($width,$height,$cachedName,$timeout,$inline); - $this->posx=$width/2; - $this->posy=$height/2; - $this->SetColor(array(255,255,255)); - } - - //--------------- - // PUBLIC METHODS - function Add($aObj) { - - if( is_array($aObj) && count($aObj) > 0 ) - $cl = $aObj[0]; - else - $cl = $aObj; - - if( $cl instanceof Text ) - $this->AddText($aObj); - elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) - $this->AddIcon($aObj); - else { - if( is_array($aObj) ) { - $n = count($aObj); - for($i=0; $i < $n; ++$i ) { - $this->plots[] = $aObj[$i]; - } - } - else { - $this->plots[] = $aObj; - } - } - } - - function SetAntiAliasing($aFlg=true) { - $this->pieaa = $aFlg; - } - - function SetColor($c) { - $this->SetMarginColor($c); - } - - - function DisplayCSIMAreas() { - $csim=""; - foreach($this->plots as $p ) { - $csim .= $p->GetCSIMareas(); - } - - $csim.= $this->legend->GetCSIMareas(); - if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { - $this->img->SetColor($this->csimcolor); - $n = count($coords[0]); - for ($i=0; $i < $n; $i++) { - if ($coords[1][$i]=="poly") { - preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); - $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); - $m = count($pts[0]); - for ($j=0; $j < $m; $j++) { - $this->img->LineTo($pts[1][$j],$pts[2][$j]); - } - } else if ($coords[1][$i]=="rect") { - $pts = preg_split('/,/', $coords[2][$i]); - $this->img->SetStartPoint($pts[0],$pts[1]); - $this->img->LineTo($pts[2],$pts[1]); - $this->img->LineTo($pts[2],$pts[3]); - $this->img->LineTo($pts[0],$pts[3]); - $this->img->LineTo($pts[0],$pts[1]); - - } - } - } - } - - // Method description - function Stroke($aStrokeFileName="") { - // If the filename is the predefined value = '_csim_special_' - // we assume that the call to stroke only needs to do enough - // to correctly generate the CSIM maps. - // We use this variable to skip things we don't strictly need - // to do to generate the image map to improve performance - // a best we can. Therefor you will see a lot of tests !$_csim in the - // code below. - $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); - - // If we are called the second time (perhaps the user has called GetHTMLImageMap() - // himself then the legends have alsready been populated once in order to get the - // CSIM coordinats. Since we do not want the legends to be populated a second time - // we clear the legends - $this->legend->Clear(); - - // We need to know if we have stroked the plot in the - // GetCSIMareas. Otherwise the CSIM hasn't been generated - // and in the case of GetCSIM called before stroke to generate - // CSIM without storing an image to disk GetCSIM must call Stroke. - $this->iHasStroked = true; - - $n = count($this->plots); - - if( $this->pieaa ) { - - if( !$_csim ) { - if( $this->background_image != "" ) { - $this->StrokeFrameBackground(); - } - else { - $this->StrokeFrame(); - $this->StrokeBackgroundGrad(); - } - } - - - $w = $this->img->width; - $h = $this->img->height; - $oldimg = $this->img->img; - - $this->img->CreateImgCanvas(2*$w,2*$h); - - $this->img->SetColor( $this->margin_color ); - $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1); - - // Make all icons *2 i size since we will be scaling down the - // imahe to do the anti aliasing - $ni = count($this->iIcons); - for($i=0; $i < $ni; ++$i) { - $this->iIcons[$i]->iScale *= 2 ; - if( $this->iIcons[$i]->iX > 1 ) - $this->iIcons[$i]->iX *= 2 ; - if( $this->iIcons[$i]->iY > 1 ) - $this->iIcons[$i]->iY *= 2 ; - } - - $this->StrokeIcons(); - - for($i=0; $i < $n; ++$i) { - if( $this->plots[$i]->posx > 1 ) - $this->plots[$i]->posx *= 2 ; - if( $this->plots[$i]->posy > 1 ) - $this->plots[$i]->posy *= 2 ; - - $this->plots[$i]->Stroke($this->img,1); - - if( $this->plots[$i]->posx > 1 ) - $this->plots[$i]->posx /= 2 ; - if( $this->plots[$i]->posy > 1 ) - $this->plots[$i]->posy /= 2 ; - } - - $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ; - $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ; - $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent, - $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent)); - - $this->img->img = $oldimg ; - $this->img->width = $w ; - $this->img->height = $h ; - - for($i=0; $i < $n; ++$i) { - $this->plots[$i]->Stroke($this->img,2); // Stroke labels - $this->plots[$i]->Legend($this); - } - - } - else { - - if( !$_csim ) { - if( $this->background_image != "" ) { - $this->StrokeFrameBackground(); - } - else { - $this->StrokeFrame(); - $this->StrokeBackgroundGrad(); - } - } - - $this->StrokeIcons(); - - for($i=0; $i < $n; ++$i) { - $this->plots[$i]->Stroke($this->img); - $this->plots[$i]->Legend($this); - } - } - - $this->legend->Stroke($this->img); - $this->footer->Stroke($this->img); - $this->StrokeTitles(); - - if( !$_csim ) { - - // Stroke texts - if( $this->texts != null ) { - $n = count($this->texts); - for($i=0; $i < $n; ++$i ) { - $this->texts[$i]->Stroke($this->img); - } - } - - if( _JPG_DEBUG ) { - $this->DisplayCSIMAreas(); - } - - // Should we do any final image transformation - if( $this->iImgTrans ) { - if( !class_exists('ImgTrans',false) ) { - require_once('jpgraph_imgtrans.php'); - //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); - } - - $tform = new ImgTrans($this->img->img); - $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, - $this->iImgTransDirection,$this->iImgTransHighQ, - $this->iImgTransMinSize,$this->iImgTransFillColor, - $this->iImgTransBorder); - } - - - // If the filename is given as the special "__handle" - // then the image handler is returned and the image is NOT - // streamed back - if( $aStrokeFileName == _IMG_HANDLER ) { - return $this->img->img; - } - else { - // Finally stream the generated picture - $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, - $aStrokeFileName); - } - } - } -} // Class - -/* EOF */ -?> + array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430), + "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38), + "water" => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388), + "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393)); + protected $theme="earth"; + protected $setslicecolors=array(); + protected $labeltype=0; // Default to percentage + protected $pie_border=true,$pie_interior_border=true; + public $value; + protected $ishadowcolor='',$ishadowdrop=4; + protected $ilabelposadj=1; + protected $legendcsimtargets = array(),$legendcsimwintargets = array(); + protected $legendcsimalts = array(); + protected $adjusted_data = array(); + public $guideline = null; + protected $guidelinemargin=10,$iShowGuideLineForSingle = false; + protected $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8; + protected $la = array(); // Holds the exact angle for each label + + //--------------- + // CONSTRUCTOR + function __construct($data) { + $this->data = array_reverse($data); + $this->title = new Text(""); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->value = new DisplayValue(); + $this->value->Show(); + $this->value->SetFormat('%.1f%%'); + $this->guideline = new LineProperty(); + } + + //--------------- + // PUBLIC METHODS + function SetCenter($x,$y=0.5) { + $this->posx = $x; + $this->posy = $y; + } + + // Enable guideline and set drwaing policy + function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) { + $this->guideline->Show($aFlg); + $this->iShowGuideLineForSingle = $aAlways; + $this->iGuideLineCurve = $aCurved; + } + + // Adjuste the distance between labels and labels and pie + function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) { + $this->iGuideVFactor=$aVFactor; + $this->iGuideLineRFactor=$aRFactor; + } + + function SetColor($aColor) { + $this->color = $aColor; + } + + function SetSliceColors($aColors) { + $this->setslicecolors = $aColors; + } + + function SetShadow($aColor='darkgray',$aDropWidth=4) { + $this->ishadowcolor = $aColor; + $this->ishadowdrop = $aDropWidth; + } + + function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { + $this->csimtargets=array_reverse($aTargets); + if( is_array($aWinTargets) ) + $this->csimwintargets=array_reverse($aWinTargets); + if( is_array($aAlts) ) + $this->csimalts=array_reverse($aAlts); + } + + function GetCSIMareas() { + return $this->csimareas; + } + + function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { + //Slice number, ellipse centre (x,y), height, width, start angle, end angle + while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; + while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; + + $sa = 2*M_PI - $sa; + $ea = 2*M_PI - $ea; + + // Special case when we have only one slice since then both start and end + // angle will be == 0 + if( abs($sa - $ea) < 0.0001 ) { + $sa=2*M_PI; $ea=0; + } + + //add coordinates of the centre to the map + $xc = floor($xc);$yc=floor($yc); + $coords = "$xc, $yc"; + + //add coordinates of the first point on the arc to the map + $xp = floor(($radius*cos($ea))+$xc); + $yp = floor($yc-$radius*sin($ea)); + $coords.= ", $xp, $yp"; + + //add coordinates every 0.2 radians + $a=$ea+0.2; + + // If we cross the 360-limit with a slice we need to handle + // the fact that end angle is smaller than start + if( $sa < $ea ) { + while ($a <= 2*M_PI) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a += 0.2; + } + $a -= 2*M_PI; + } + + + while ($a < $sa) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a += 0.2; + } + + //Add the last point on the arc + $xp = floor($radius*cos($sa)+$xc); + $yp = floor($yc-$radius*sin($sa)); + $coords.= ", $xp, $yp"; + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= "csimtargets[$i]."\""; + $tmp=""; + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + if( !empty($this->csimalts[$i]) ) { + $tmp=sprintf($this->csimalts[$i],$this->data[$i]); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + + function SetTheme($aTheme) { + if( in_array($aTheme,array_keys($this->themearr)) ) + $this->theme = $aTheme; + else + JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme"); + } + + function ExplodeSlice($e,$radius=20) { + if( ! is_integer($e) ) + JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer'); + $this->explode_radius[$e]=$radius; + } + + function ExplodeAll($radius=20) { + $this->explode_all=true; + $this->explode_r = $radius; + } + + function Explode($aExplodeArr) { + if( !is_array($aExplodeArr) ) { + JpGraphError::RaiseL(15003); + //("Argument to PiePlot::Explode() must be an array with integer distances."); + } + $this->explode_radius = $aExplodeArr; + } + + function SetStartAngle($aStart) { + if( $aStart < 0 || $aStart > 360 ) { + JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.'); + } + if( $aStart == 0 ) { + $this->startangle = 0; + } + else { + $this->startangle = 360-$aStart; + $this->startangle *= M_PI/180; + } + } + + // Size in percentage + function SetSize($aSize) { + if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) ) + $this->radius = $aSize; + else + JpGraphError::RaiseL(15006); + //("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]"); + } + + // Set label arrays + function SetLegends($aLegend) { + $this->legends = $aLegend; + } + + // Set text labels for slices + function SetLabels($aLabels,$aLblPosAdj="auto") { + $this->labels = array_reverse($aLabels); + $this->ilabelposadj=$aLblPosAdj; + } + + function SetLabelPos($aLblPosAdj) { + $this->ilabelposadj=$aLblPosAdj; + } + + // Should we display actual value or percentage? + function SetLabelType($aType) { + if( $aType < 0 || $aType > 2 ) + JpGraphError::RaiseL(15008,$aType); + //("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t)."); + $this->labeltype = $aType; + } + + // Deprecated. + function SetValueType($aType) { + $this->SetLabelType($aType); + } + + // Should the circle around a pie plot be displayed + function ShowBorder($exterior=true,$interior=true) { + $this->pie_border = $exterior; + $this->pie_interior_border = $interior; + } + + // Setup the legends + function Legend($graph) { + $colors = array_keys($graph->img->rgb->rgb_table); + sort($colors); + $ta=$this->themearr[$this->theme]; + $n = count($this->data); + + if( $this->setslicecolors==null ) { + $numcolors=count($ta); + if( class_exists('PiePlot3D',false) && ($this instanceof PiePlot3D) ) { + $ta = array_reverse(array_slice($ta,0,$n)); + } + } + else { + $this->setslicecolors = array_slice($this->setslicecolors,0,$n); + $numcolors=count($this->setslicecolors); + if( $graph->pieaa && !($this instanceof PiePlot3D) ) { + $this->setslicecolors = array_reverse($this->setslicecolors); + } + } + + $sum=0; + for($i=0; $i < $n; ++$i) + $sum += $this->data[$i]; + + // Bail out with error if the sum is 0 + if( $sum==0 ) + JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!"); + + // Make sure we don't plot more values than data points + // (in case the user added more legends than data points) + $n = min(count($this->legends),count($this->data)); + if( $this->legends != "" ) { + $this->legends = array_reverse(array_slice($this->legends,0,$n)); + } + for( $i=$n-1; $i >= 0; --$i ) { + $l = $this->legends[$i]; + // Replace possible format with actual values + if( count($this->csimalts) > $i ) { + $fmt = $this->csimalts[$i]; + } + else { + $fmt = "%d"; // Deafult Alt if no other has been specified + } + if( $this->labeltype==0 ) { + $l = sprintf($l,100*$this->data[$i]/$sum); + $alt = sprintf($fmt,$this->data[$i]); + + } + elseif( $this->labeltype == 1) { + $l = sprintf($l,$this->data[$i]); + $alt = sprintf($fmt,$this->data[$i]); + + } + else { + $l = sprintf($l,$this->adjusted_data[$i]); + $alt = sprintf($fmt,$this->adjusted_data[$i]); + } + + if( empty($this->csimwintargets[$i]) ) { + $wintarg = ''; + } + else { + $wintarg = $this->csimwintargets[$i]; + } + + if( $this->setslicecolors==null ) { + $graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt,$wintarg); + } + else { + $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt,$wintarg); + } + } + } + + // Adjust the rounded percetage value so that the sum of + // of the pie slices are always 100% + // Using the Hare/Niemeyer method + function AdjPercentage($aData,$aPrec=0) { + $mul=100; + if( $aPrec > 0 && $aPrec < 3 ) { + if( $aPrec == 1 ) + $mul=1000; + else + $mul=10000; + } + + $tmp = array(); + $result = array(); + $quote_sum=0; + $n = count($aData) ; + for( $i=0, $sum=0; $i < $n; ++$i ) + $sum+=$aData[$i]; + foreach($aData as $index => $value) { + $tmp_percentage=$value/$sum*$mul; + $result[$index]=floor($tmp_percentage); + $tmp[$index]=$tmp_percentage-$result[$index]; + $quote_sum+=$result[$index]; + } + if( $quote_sum == $mul) { + if( $mul > 100 ) { + $tmp = $mul / 100; + for( $i=0; $i < $n; ++$i ) { + $result[$i] /= $tmp ; + } + } + return $result; + } + arsort($tmp,SORT_NUMERIC); + reset($tmp); + for($i=0; $i < $mul-$quote_sum; $i++) + { + $result[key($tmp)]++; + next($tmp); + } + if( $mul > 100 ) { + $tmp = $mul / 100; + for( $i=0; $i < $n; ++$i ) { + $result[$i] /= $tmp ; + } + } + return $result; + } + + + function Stroke($img,$aaoption=0) { + // aaoption is used to handle antialias + // aaoption == 0 a normal pie + // aaoption == 1 just the body + // aaoption == 2 just the values + + // Explode scaling. If anti alias we scale the image + // twice and we also need to scale the exploding distance + $expscale = $aaoption === 1 ? 2 : 1; + + if( $this->labeltype == 2 ) { + // Adjust the data so that it will add up to 100% + $this->adjusted_data = $this->AdjPercentage($this->data); + } + + $colors = array_keys($img->rgb->rgb_table); + sort($colors); + $ta=$this->themearr[$this->theme]; + $n = count($this->data); + + if( $this->setslicecolors==null ) { + $numcolors=count($ta); + } + else { + // We need to create an array of colors as long as the data + // since we need to reverse it to get the colors in the right order + $numcolors=count($this->setslicecolors); + $i = 2*$numcolors; + while( $n > $i ) { + $this->setslicecolors = array_merge($this->setslicecolors,$this->setslicecolors); + $i += $n; + } + $tt = array_slice($this->setslicecolors,0,$n % $numcolors); + $this->setslicecolors = array_merge($this->setslicecolors,$tt); + $this->setslicecolors = array_reverse($this->setslicecolors); + } + + // Draw the slices + $sum=0; + for($i=0; $i < $n; ++$i) + $sum += $this->data[$i]; + + // Bail out with error if the sum is 0 + if( $sum==0 ) { + JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie."); + } + + // Set up the pie-circle + if( $this->radius <= 1 ) { + $radius = floor($this->radius*min($img->width,$img->height)); + } + else { + $radius = $aaoption === 1 ? $this->radius*2 : $this->radius; + } + + if( $this->posx <= 1 && $this->posx > 0 ) { + $xc = round($this->posx*$img->width); + } + else { + $xc = $this->posx ; + } + + if( $this->posy <= 1 && $this->posy > 0 ) { + $yc = round($this->posy*$img->height); + } + else { + $yc = $this->posy ; + } + + $n = count($this->data); + + if( $this->explode_all ) { + for($i=0; $i < $n; ++$i) { + $this->explode_radius[$i]=$this->explode_r; + } + } + + // If we have a shadow and not just drawing the labels + if( $this->ishadowcolor != "" && $aaoption !== 2) { + $accsum=0; + $angle2 = $this->startangle; + $img->SetColor($this->ishadowcolor); + for($i=0; $sum > 0 && $i < $n; ++$i) { + $j = $n-$i-1; + $d = $this->data[$i]; + $angle1 = $angle2; + $accsum += $d; + $angle2 = $this->startangle+2*M_PI*$accsum/$sum; + if( empty($this->explode_radius[$j]) ) { + $this->explode_radius[$j]=0; + } + + if( $d < 0.00001 ) continue; + + $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); + + $xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale; + $ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale; + + $xcm += $this->ishadowdrop*$expscale; + $ycm += $this->ishadowdrop*$expscale; + + $_sa = round($angle1*180/M_PI); + $_ea = round($angle2*180/M_PI); + + // The CakeSlice method draws a full circle in case of start angle = end angle + // for pie slices we don't want this behaviour unless we only have one + // slice in the pie in case it is the wanted behaviour + if( $_ea-$_sa > 0.1 || $n==1 ) { + $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1, + $angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor); + } + } + } + + //-------------------------------------------------------------------------------- + // This is the main loop to draw each cake slice + //-------------------------------------------------------------------------------- + + // Set up the accumulated sum, start angle for first slice and border color + $accsum=0; + $angle2 = $this->startangle; + $img->SetColor($this->color); + + // Loop though all the slices if there is a pie to draw (sum>0) + // There are n slices in total + for($i=0; $sum>0 && $i < $n; ++$i) { + + // $j is the actual index used for the slice + $j = $n-$i-1; + + // Make sure we havea valid distance to explode the slice + if( empty($this->explode_radius[$j]) ) { + $this->explode_radius[$j]=0; + } + + // The actual numeric value for the slice + $d = $this->data[$i]; + + $angle1 = $angle2; + + // Accumlate the sum + $accsum += $d; + + // The new angle when we add the "size" of this slice + // angle1 is then the start and angle2 the end of this slice + $angle2 = $this->NormAngle($this->startangle+2*M_PI*$accsum/$sum); + + // We avoid some trouble by not allowing end angle to be 0, in that case + // we translate to 360 + + // la is used to hold the label angle, which is centered on the slice + if( $angle2 < 0.0001 && $angle1 > 0.0001 ) { + $this->la[$i] = 2*M_PI - (abs(2*M_PI-$angle1)/2.0+$angle1); + } + elseif( $angle1 > $angle2 ) { + // The case where the slice crosses the 3 a'clock line + // Remember that the slices are counted clockwise and + // labels are counted counter clockwise so we need to revert with 2 PI + $this->la[$i] = 2*M_PI-$this->NormAngle($angle1 + ((2*M_PI - $angle1)+$angle2)/2); + } + else { + $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); + } + + // Too avoid rounding problems we skip the slice if it is too small + if( $d < 0.00001 ) continue; + + // If the user has specified an array of colors for each slice then use + // that a color otherwise use the theme array (ta) of colors + if( $this->setslicecolors==null ) { + $slicecolor=$colors[$ta[$i%$numcolors]]; + } + else { + $slicecolor=$this->setslicecolors[$i%$numcolors]; + } + +// $_sa = round($angle1*180/M_PI); +// $_ea = round($angle2*180/M_PI); +// $_la = round($this->la[$i]*180/M_PI); +// echo "Slice#$i: ang1=$_sa , ang2=$_ea, la=$_la, color=$slicecolor
      "; + + + // If we have enabled antialias then we don't draw any border so + // make the bordedr color the same as the slice color + if( $this->pie_interior_border && $aaoption===0 ) { + $img->SetColor($this->color); + } + else { + $img->SetColor($slicecolor); + } + $arccolor = $this->pie_border && $aaoption===0 ? $this->color : ""; + + // Calculate the x,y coordinates for the base of this slice taking + // the exploded distance into account. Here we use the mid angle as the + // ray of extension and we have the mid angle handy as it is also the + // label angle + $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale; + $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale; + + // If we are not just drawing the labels then draw this cake slice + if( $aaoption !== 2 ) { + + $_sa = round($angle1*180/M_PI); + $_ea = round($angle2*180/M_PI); + $_la = round($this->la[$i]*180/M_PI); + //echo "[$i] sa=$_sa, ea=$_ea, la[$i]=$_la, (color=$slicecolor)
      "; + + // The CakeSlice method draws a full circle in case of start angle = end angle + // for pie slices we want this in case the slice have a value larger than 99% of the + // total sum + if( abs($_ea-$_sa) >= 1 || $d == $sum ) { + $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,$_sa,$_ea,$slicecolor,$arccolor); + } + } + + // If the CSIM is used then make sure we register a CSIM area for this slice as well + if( $this->csimtargets && $aaoption !== 1 ) { + $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2); + } + } + + // Format the titles for each slice + if( $aaoption !== 2 ) { + for( $i=0; $i < $n; ++$i) { + if( $this->labeltype==0 ) { + if( $sum != 0 ) + $l = 100.0*$this->data[$i]/$sum; + else + $l = 0.0; + } + elseif( $this->labeltype==1 ) { + $l = $this->data[$i]*1.0; + } + else { + $l = $this->adjusted_data[$i]; + } + if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) + $this->labels[$i]=sprintf($this->labels[$i],$l); + else + $this->labels[$i]=$l; + } + } + + if( $this->value->show && $aaoption !== 1 ) { + $this->StrokeAllLabels($img,$xc,$yc,$radius); + } + + // Adjust title position + if( $aaoption !== 1 ) { + $this->title->SetPos($xc, + $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin, + "center","bottom"); + $this->title->Stroke($img); + } + + } + + //--------------- + // PRIVATE METHODS + + function NormAngle($a) { + while( $a < 0 ) $a += 2*M_PI; + while( $a > 2*M_PI ) $a -= 2*M_PI; + return $a; + } + + function Quadrant($a) { + $a=$this->NormAngle($a); + if( $a > 0 && $a <= M_PI/2 ) + return 0; + if( $a > M_PI/2 && $a <= M_PI ) + return 1; + if( $a > M_PI && $a <= 1.5*M_PI ) + return 2; + if( $a > 1.5*M_PI ) + return 3; + } + + function StrokeGuideLabels($img,$xc,$yc,$radius) { + $n = count($this->labels); + + //----------------------------------------------------------------------- + // Step 1 of the algorithm is to construct a number of clusters + // a cluster is defined as all slices within the same quadrant (almost) + // that has an angular distance less than the treshold + //----------------------------------------------------------------------- + $tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster + $incluster=false; // flag if we are currently in a cluster or not + $clusters = array(); // array of clusters + $cidx=-1; // running cluster index + + // Go through all the labels and construct a number of clusters + for($i=0; $i < $n-1; ++$i) { + // Calc the angle distance between two consecutive slices + $a1=$this->la[$i]; + $a2=$this->la[$i+1]; + $q1 = $this->Quadrant($a1); + $q2 = $this->Quadrant($a2); + $diff = abs($a1-$a2); + if( $diff < $tresh_hold ) { + if( $incluster ) { + $clusters[$cidx][1]++; + // Each cluster can only cover one quadrant + // Do we cross a quadrant ( and must break the cluster) + if( $q1 != $q2 ) { + // If we cross a quadrant boundary we normally start a + // new cluster. However we need to take the 12'a clock + // and 6'a clock positions into a special consideration. + // Case 1: WE go from q=1 to q=2 if the last slice on + // the cluster for q=1 is close to 12'a clock and the + // first slice in q=0 is small we extend the previous + // cluster + if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) { + if( $i < $n-2 ) { + $a3 = $this->la[$i+2]; + // If there isn't a cluster coming up with the next-next slice + // we extend the previous cluster to cover this slice as well + if( abs($a3-$a2) >= $tresh_hold ) { + $clusters[$cidx][1]++; + $i++; + } + } + } + elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) { + if( $i < $n-2 ) { + $a3 = $this->la[$i+2]; + // If there isn't a cluster coming up with the next-next slice + // we extend the previous cluster to cover this slice as well + if( abs($a3-$a2) >= $tresh_hold ) { + $clusters[$cidx][1]++; + $i++; + } + } + } + + if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) { + $clusters[$cidx][1]++; + $i++; + } + + $incluster = false; + } + } + elseif( $q1 == $q2) { + $incluster = true; + // Now we have a special case for quadrant 0. If we previously + // have a cluster of one in quadrant 0 we just extend that + // cluster. If we don't do this then we risk that the label + // for the cluster of one will cross the guide-line + if( $q1 == 0 && $cidx > -1 && + $clusters[$cidx][1] == 1 && + $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) { + $clusters[$cidx][1]++; + } + else { + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + } + else { + // Create a "cluster" of one since we are just crossing + // a quadrant + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + } + else { + if( $incluster ) { + // Add the last slice + $clusters[$cidx][1]++; + $incluster = false; + } + else { // Create a "cluster" of one + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + } + } + // Handle the very last slice + if( $incluster ) { + $clusters[$cidx][1]++; + } + else { // Create a "cluster" of one + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + + /* + if( true ) { + // Debug printout in labels + for( $i=0; $i <= $cidx; ++$i ) { + for( $j=0; $j < $clusters[$i][1]; ++$j ) { + $a = $this->la[$clusters[$i][0]+$j]; + $aa = round($a*180/M_PI); + $q = $this->Quadrant($a); + $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j"; + } + } + } + */ + + //----------------------------------------------------------------------- + // Step 2 of the algorithm is use the clusters and draw the labels + // and guidelines + //----------------------------------------------------------------------- + + // We use the font height as the base factor for how far we need to + // spread the labels in the Y-direction. + $this->value->ApplyFont($img); + $fh = $img->GetFontHeight(); + $origvstep=$fh*$this->iGuideVFactor; + $this->value->SetMargin(0); + + // Number of clusters found + $nc = count($clusters); + + // Walk through all the clusters + for($i=0; $i < $nc; ++$i) { + + // Start angle and number of slices in this cluster + $csize = $clusters[$i][1]; + $a = $this->la[$clusters[$i][0]]; + $q = $this->Quadrant($a); + + // Now set up the start and end conditions to make sure that + // in each cluster we walk through the all the slices starting with the slice + // closest to the equator. Since all slices are numbered clockwise from "3'a clock" + // we have different conditions depending on in which quadrant the slice lies within. + if( $q == 0 ) { + $start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep; + } + elseif( $q == 1 ) { + $start = 0; $idx = $start; $step = 1; $vstep = -$origvstep; + } + elseif( $q == 2 ) { + $start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep; + } + elseif( $q == 3 ) { + $start = 0; $idx = $start; $step = 1; $vstep = $origvstep; + } + + // Walk through all slices within this cluster + for($j=0; $j < $csize; ++$j) { + // Now adjust the position of the labels in each cluster starting + // with the slice that is closest to the equator of the pie + $a = $this->la[$clusters[$i][0]+$idx]; + + // Guide line start in the center of the arc of the slice + $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; + $x = round($r*cos($a)+$xc); + $y = round($yc-$r*sin($a)); + + // The distance from the arc depends on chosen font and the "R-Factor" + $r += $fh*$this->iGuideLineRFactor; + + // Should the labels be placed curved along the pie or in straight columns + // outside the pie? + if( $this->iGuideLineCurve ) + $xt=round($r*cos($a)+$xc); + + // If this is the first slice in the cluster we need some first time + // proessing + if( $idx == $start ) { + if( ! $this->iGuideLineCurve ) + $xt=round($r*cos($a)+$xc); + $yt=round($yc-$r*sin($a)); + + // Some special consideration in case this cluster starts + // in quadrant 1 or 3 very close to the "equator" (< 20 degrees) + // and the previous clusters last slice is within the tolerance. + // In that case we add a font height to this labels Y-position + // so it doesn't collide with + // the slice in the previous cluster + $prevcluster = ($i + ($nc-1) ) % $nc; + $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1; + if( $q == 1 && $a > 160*M_PI/180 ) { + // Get the angle for the previous clusters last slice + $diff = abs($a-$this->la[$previdx]); + if( $diff < $tresh_hold ) { + $yt -= $fh; + } + } + elseif( $q == 3 && $a > 340*M_PI/180 ) { + // We need to subtract 360 to compare angle distance between + // q=0 and q=3 + $diff = abs($a-$this->la[$previdx]-360*M_PI/180); + if( $diff < $tresh_hold ) { + $yt += $fh; + } + } + + } + else { + // The step is at minimum $vstep but if the slices are relatively large + // we make sure that we add at least a step that corresponds to the vertical + // distance between the centers at the arc on the slice + $prev_a = $this->la[$clusters[$i][0]+($idx-$step)]; + $dy = abs($radius*(sin($a)-sin($prev_a))*1.2); + if( $vstep > 0 ) + $yt += max($vstep,$dy); + else + $yt += min($vstep,-$dy); + } + + $label = $this->labels[$clusters[$i][0]+$idx]; + + if( $csize == 1 ) { + // A "meta" cluster with only one slice + $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; + $rr = $r+$img->GetFontHeight()/2; + $xt=round($rr*cos($a)+$xc); + $yt=round($yc-$rr*sin($a)); + $this->StrokeLabel($label,$img,$xc,$yc,$a,$r); + if( $this->iShowGuideLineForSingle ) + $this->guideline->Stroke($img,$x,$y,$xt,$yt); + } + else { + $this->guideline->Stroke($img,$x,$y,$xt,$yt); + if( $q==1 || $q==2 ) { + // Left side of Pie + $this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt); + $lbladj = -$this->guidelinemargin-5; + $this->value->halign = "right"; + $this->value->valign = "center"; + } + else { + // Right side of pie + $this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt); + $lbladj = $this->guidelinemargin+5; + $this->value->halign = "left"; + $this->value->valign = "center"; + } + $this->value->Stroke($img,$label,$xt+$lbladj,$yt); + } + + // Udate idx to point to next slice in the cluster to process + $idx += $step; + } + } + } + + function StrokeAllLabels($img,$xc,$yc,$radius) { + // First normalize all angles for labels + $n = count($this->la); + for($i=0; $i < $n; ++$i) { + $this->la[$i] = $this->NormAngle($this->la[$i]); + } + if( $this->guideline->iShow ) { + $this->StrokeGuideLabels($img,$xc,$yc,$radius); + } + else { + $n = count($this->labels); + for($i=0; $i < $n; ++$i) { + $this->StrokeLabel($this->labels[$i],$img,$xc,$yc, + $this->la[$i], + $radius + $this->explode_radius[$n-1-$i]); + } + } + } + + // Position the labels of each slice + function StrokeLabel($label,$img,$xc,$yc,$a,$r) { + + // Default value + if( $this->ilabelposadj === 'auto' ) + $this->ilabelposadj = 0.65; + + // We position the values diferently depending on if they are inside + // or outside the pie + if( $this->ilabelposadj < 1.0 ) { + + $this->value->SetAlign('center','center'); + $this->value->margin = 0; + + $xt=round($this->ilabelposadj*$r*cos($a)+$xc); + $yt=round($yc-$this->ilabelposadj*$r*sin($a)); + + $this->value->Stroke($img,$label,$xt,$yt); + } + else { + + $this->value->halign = "left"; + $this->value->valign = "top"; + $this->value->margin = 0; + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + $this->value->ApplyFont($img); + $h=$img->GetTextHeight($label); + // For numeric values the format of the display value + // must be taken into account + if( is_numeric($label) ) { + if( $label > 0 ) + $w=$img->GetTextWidth(sprintf($this->value->format,$label)); + else + $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); + } + else + $w=$img->GetTextWidth($label); + + if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) { + $r *= $this->ilabelposadj; + } + + $r += $img->GetFontHeight()/1.5; + + $xt=round($r*cos($a)+$xc); + $yt=round($yc-$r*sin($a)); + + // Normalize angle + while( $a < 0 ) $a += 2*M_PI; + while( $a > 2*M_PI ) $a -= 2*M_PI; + + if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); + + if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; + if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; + + $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h); + } + } +} // Class + + +//=================================================== +// CLASS PiePlotC +// Description: Same as a normal pie plot but with a +// filled circle in the center +//=================================================== +class PiePlotC extends PiePlot { + private $imidsize=0.5; // Fraction of total width + private $imidcolor='white'; + public $midtitle=''; + private $middlecsimtarget='',$middlecsimwintarget='',$middlecsimalt=''; + + function __construct($data,$aCenterTitle='') { + parent::__construct($data); + $this->midtitle = new Text(); + $this->midtitle->ParagraphAlign('center'); + } + + function SetMid($aTitle,$aColor='white',$aSize=0.5) { + $this->midtitle->Set($aTitle); + + $this->imidsize = $aSize ; + $this->imidcolor = $aColor ; + } + + function SetMidTitle($aTitle) { + $this->midtitle->Set($aTitle); + } + + function SetMidSize($aSize) { + $this->imidsize = $aSize ; + } + + function SetMidColor($aColor) { + $this->imidcolor = $aColor ; + } + + function SetMidCSIM($aTarget,$aAlt='',$aWinTarget='') { + $this->middlecsimtarget = $aTarget; + $this->middlecsimwintarget = $aWinTarget; + $this->middlecsimalt = $aAlt; + } + + function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { + //Slice number, ellipse centre (x,y), radius, start angle, end angle + while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; + while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; + + $sa = 2*M_PI - $sa; + $ea = 2*M_PI - $ea; + + // Special case when we have only one slice since then both start and end + // angle will be == 0 + if( abs($sa - $ea) < 0.0001 ) { + $sa=2*M_PI; $ea=0; + } + + // Add inner circle first point + $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); + $yp = floor($yc-($this->imidsize*$radius*sin($ea))); + $coords = "$xp, $yp"; + + //add coordinates every 0.25 radians + $a=$ea+0.25; + + // If we cross the 360-limit with a slice we need to handle + // the fact that end angle is smaller than start + if( $sa < $ea ) { + while ($a <= 2*M_PI) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a += 0.25; + } + $a -= 2*M_PI; + } + + while ($a < $sa) { + $xp = floor(($this->imidsize*$radius*cos($a)+$xc)); + $yp = floor($yc-($this->imidsize*$radius*sin($a))); + $coords.= ", $xp, $yp"; + $a += 0.25; + } + + // Make sure we end at the last point + $xp = floor(($this->imidsize*$radius*cos($sa)+$xc)); + $yp = floor($yc-($this->imidsize*$radius*sin($sa))); + $coords.= ", $xp, $yp"; + + // Straight line to outer circle + $xp = floor($radius*cos($sa)+$xc); + $yp = floor($yc-$radius*sin($sa)); + $coords.= ", $xp, $yp"; + + //add coordinates every 0.25 radians + $a=$sa - 0.25; + while ($a > $ea) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a -= 0.25; + } + + //Add the last point on the arc + $xp = floor($radius*cos($ea)+$xc); + $yp = floor($yc-$radius*sin($ea)); + $coords.= ", $xp, $yp"; + + // Close the arc + $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); + $yp = floor($yc-($this->imidsize*$radius*sin($ea))); + $coords .= ", $xp, $yp"; + + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= "csimtargets[$i]."\""; + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + if( !empty($this->csimalts[$i]) ) { + $tmp=sprintf($this->csimalts[$i],$this->data[$i]); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + + function Stroke($img,$aaoption=0) { + + // Stroke the pie but don't stroke values + $tmp = $this->value->show; + $this->value->show = false; + parent::Stroke($img,$aaoption); + $this->value->show = $tmp; + + $xc = round($this->posx*$img->width); + $yc = round($this->posy*$img->height); + + $radius = floor($this->radius * min($img->width,$img->height)) ; + + + if( $this->imidsize > 0 && $aaoption !== 2 ) { + + if( $this->ishadowcolor != "" ) { + $img->SetColor($this->ishadowcolor); + $img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop, + round($radius*$this->imidsize)); + } + + $img->SetColor($this->imidcolor); + $img->FilledCircle($xc,$yc,round($radius*$this->imidsize)); + + if( $this->pie_border && $aaoption === 0 ) { + $img->SetColor($this->color); + $img->Circle($xc,$yc,round($radius*$this->imidsize)); + } + + if( !empty($this->middlecsimtarget) ) + $this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize)); + + } + + if( $this->value->show && $aaoption !== 1) { + $this->StrokeAllLabels($img,$xc,$yc,$radius); + $this->midtitle->SetPos($xc,$yc,'center','center'); + $this->midtitle->Stroke($img); + } + + } + + function AddMiddleCSIM($xc,$yc,$r) { + $xc=round($xc);$yc=round($yc);$r=round($r); + $this->csimareas .= "middlecsimtarget."\""; + if( !empty($this->middlecsimwintarget) ) { + $this->csimareas .= " target=\"".$this->middlecsimwintarget."\""; + } + if( !empty($this->middlecsimalt) ) { + $tmp = $this->middlecsimalt; + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + + function StrokeLabel($label,$img,$xc,$yc,$a,$r) { + + if( $this->ilabelposadj === 'auto' ) + $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize; + + parent::StrokeLabel($label,$img,$xc,$yc,$a,$r); + + } + +} + + +//=================================================== +// CLASS PieGraph +// Description: +//=================================================== +class PieGraph extends Graph { + private $posx, $posy, $radius; + private $legends=array(); + public $plots=array(); + public $pieaa = false ; + //--------------- + // CONSTRUCTOR + function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { + parent::__construct($width,$height,$cachedName,$timeout,$inline); + $this->posx=$width/2; + $this->posy=$height/2; + $this->SetColor(array(255,255,255)); + } + + //--------------- + // PUBLIC METHODS + function Add($aObj) { + + if( is_array($aObj) && count($aObj) > 0 ) + $cl = $aObj[0]; + else + $cl = $aObj; + + if( $cl instanceof Text ) + $this->AddText($aObj); + elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) + $this->AddIcon($aObj); + else { + if( is_array($aObj) ) { + $n = count($aObj); + for($i=0; $i < $n; ++$i ) { + $this->plots[] = $aObj[$i]; + } + } + else { + $this->plots[] = $aObj; + } + } + } + + function SetAntiAliasing($aFlg=true) { + $this->pieaa = $aFlg; + } + + function SetColor($c) { + $this->SetMarginColor($c); + } + + + function DisplayCSIMAreas() { + $csim=""; + foreach($this->plots as $p ) { + $csim .= $p->GetCSIMareas(); + } + + $csim.= $this->legend->GetCSIMareas(); + if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { + $this->img->SetColor($this->csimcolor); + $n = count($coords[0]); + for ($i=0; $i < $n; $i++) { + if ($coords[1][$i]=="poly") { + preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); + $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); + $m = count($pts[0]); + for ($j=0; $j < $m; $j++) { + $this->img->LineTo($pts[1][$j],$pts[2][$j]); + } + } else if ($coords[1][$i]=="rect") { + $pts = preg_split('/,/', $coords[2][$i]); + $this->img->SetStartPoint($pts[0],$pts[1]); + $this->img->LineTo($pts[2],$pts[1]); + $this->img->LineTo($pts[2],$pts[3]); + $this->img->LineTo($pts[0],$pts[3]); + $this->img->LineTo($pts[0],$pts[1]); + + } + } + } + } + + // Method description + function Stroke($aStrokeFileName="") { + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // If we are called the second time (perhaps the user has called GetHTMLImageMap() + // himself then the legends have alsready been populated once in order to get the + // CSIM coordinats. Since we do not want the legends to be populated a second time + // we clear the legends + $this->legend->Clear(); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + $n = count($this->plots); + + if( $this->pieaa ) { + + if( !$_csim ) { + if( $this->background_image != "" ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + $this->StrokeBackgroundGrad(); + } + } + + + $w = $this->img->width; + $h = $this->img->height; + $oldimg = $this->img->img; + + $this->img->CreateImgCanvas(2*$w,2*$h); + + $this->img->SetColor( $this->margin_color ); + $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1); + + // Make all icons *2 i size since we will be scaling down the + // imahe to do the anti aliasing + $ni = count($this->iIcons); + for($i=0; $i < $ni; ++$i) { + $this->iIcons[$i]->iScale *= 2 ; + if( $this->iIcons[$i]->iX > 1 ) + $this->iIcons[$i]->iX *= 2 ; + if( $this->iIcons[$i]->iY > 1 ) + $this->iIcons[$i]->iY *= 2 ; + } + + $this->StrokeIcons(); + + for($i=0; $i < $n; ++$i) { + if( $this->plots[$i]->posx > 1 ) + $this->plots[$i]->posx *= 2 ; + if( $this->plots[$i]->posy > 1 ) + $this->plots[$i]->posy *= 2 ; + + $this->plots[$i]->Stroke($this->img,1); + + if( $this->plots[$i]->posx > 1 ) + $this->plots[$i]->posx /= 2 ; + if( $this->plots[$i]->posy > 1 ) + $this->plots[$i]->posy /= 2 ; + } + + $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ; + $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ; + $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent, + $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent)); + + $this->img->img = $oldimg ; + $this->img->width = $w ; + $this->img->height = $h ; + + for($i=0; $i < $n; ++$i) { + $this->plots[$i]->Stroke($this->img,2); // Stroke labels + $this->plots[$i]->Legend($this); + } + + } + else { + + if( !$_csim ) { + if( $this->background_image != "" ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + $this->StrokeBackgroundGrad(); + } + } + + $this->StrokeIcons(); + + for($i=0; $i < $n; ++$i) { + $this->plots[$i]->Stroke($this->img); + $this->plots[$i]->Legend($this); + } + } + + $this->legend->Stroke($this->img); + $this->footer->Stroke($this->img); + $this->StrokeTitles(); + + if( !$_csim ) { + + // Stroke texts + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i ) { + $this->texts[$i]->Stroke($this->img); + } + } + + if( _JPG_DEBUG ) { + $this->DisplayCSIMAreas(); + } + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + } +} // Class + +/* EOF */ +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_pie3d.php b/ext/jpgraph-3.0.7/src/jpgraph_pie3d.php index 258aa80..28e32a4 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_pie3d.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_pie3d.php @@ -1,933 +1,933 @@ -radius = 0.5; - $this->data = $data; - $this->title = new Text(""); - $this->title->SetFont(FF_FONT1,FS_BOLD); - $this->value = new DisplayValue(); - $this->value->Show(); - $this->value->SetFormat('%.0f%%'); - } - - //--------------- - // PUBLIC METHODS - - // Set label arrays - function SetLegends($aLegend) { - $this->legends = array_reverse(array_slice($aLegend,0,count($this->data))); - } - - function SetSliceColors($aColors) { - $this->setslicecolors = $aColors; - } - - function Legend($aGraph) { - parent::Legend($aGraph); - $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol); - } - - function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { - $this->csimtargets = $aTargets; - $this->csimwintargets = $aWinTargets; - $this->csimalts = $aAlts; - } - - // Should the slices be separated by a line? If color is specified as "" no line - // will be used to separate pie slices. - function SetEdge($aColor='black',$aWeight=1) { - $this->edgecolor = $aColor; - $this->edgeweight = $aWeight; - } - - // Specify projection angle for 3D in degrees - // Must be between 20 and 70 degrees - function SetAngle($a) { - if( $a<5 || $a>90 ) { - JpGraphError::RaiseL(14002); - //("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees."); - } - else { - $this->angle = $a; - } - } - - function Add3DSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle - - $sa *= M_PI/180; - $ea *= M_PI/180; - - //add coordinates of the centre to the map - $coords = "$xc, $yc"; - - //add coordinates of the first point on the arc to the map - $xp = floor($width*cos($sa)/2+$xc); - $yp = floor($yc-$height*sin($sa)/2); - $coords.= ", $xp, $yp"; - - //If on the front half, add the thickness offset - if ($sa >= M_PI && $sa <= 2*M_PI*1.01) { - $yp = floor($yp+$thick); - $coords.= ", $xp, $yp"; - } - - //add coordinates every 0.2 radians - $a=$sa+0.2; - while ($a<$ea) { - $xp = floor($width*cos($a)/2+$xc); - if ($a >= M_PI && $a <= 2*M_PI*1.01) { - $yp = floor($yc-($height*sin($a)/2)+$thick); - } else { - $yp = floor($yc-$height*sin($a)/2); - } - $coords.= ", $xp, $yp"; - $a += 0.2; - } - - //Add the last point on the arc - $xp = floor($width*cos($ea)/2+$xc); - $yp = floor($yc-$height*sin($ea)/2); - - - if ($ea >= M_PI && $ea <= 2*M_PI*1.01) { - $coords.= ", $xp, ".floor($yp+$thick); - } - $coords.= ", $xp, $yp"; - $alt=''; - - if( !empty($this->csimtargets[$i]) ) { - $this->csimareas .= "csimtargets[$i]."\""; - - if( !empty($this->csimwintargets[$i]) ) { - $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; - } - - if( !empty($this->csimalts[$i]) ) { - $tmp=sprintf($this->csimalts[$i],$this->data[$i]); - $this->csimareas .= "alt=\"$tmp\" title=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - - } - - function SetLabels($aLabels,$aLblPosAdj="auto") { - $this->labels = $aLabels; - $this->ilabelposadj=$aLblPosAdj; - } - - - // Distance from the pie to the labels - function SetLabelMargin($m) { - $this->value->SetMargin($m); - } - - // Show a thin line from the pie to the label for a specific slice - function ShowLabelHint($f=true) { - $this->showlabelhint=$f; - } - - // Set color of hint line to label for each slice - function SetLabelHintColor($c) { - $this->labelhintcolor=$c; - } - - function SetHeight($aHeight) { - $this->iThickness = $aHeight; - } - - - // Normalize Angle between 0-360 - function NormAngle($a) { - // Normalize anle to 0 to 2M_PI - // - if( $a > 0 ) { - while($a > 360) $a -= 360; - } - else { - while($a < 0) $a += 360; - } - if( $a < 0 ) - $a = 360 + $a; - - if( $a == 360 ) $a=0; - return $a; - } - - - - // Draw one 3D pie slice at position ($xc,$yc) with height $z - function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) { - - // Due to the way the 3D Pie algorithm works we are - // guaranteed that any slice we get into this method - // belongs to either the left or right side of the - // pie ellipse. Hence, no slice will cross 90 or 270 - // point. - if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) { - JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice'); - exit(1); - } - - $p[] = array(); - - // Setup pre-calculated values - $rsa = $sa/180*M_PI; // to Rad - $rea = $ea/180*M_PI; // to Rad - $sinsa = sin($rsa); - $cossa = cos($rsa); - $sinea = sin($rea); - $cosea = cos($rea); - - // p[] is the points for the overall slice and - // pt[] is the points for the top pie - - // Angular step when approximating the arc with a polygon train. - $step = 0.05; - - if( $sa >= 270 ) { - if( $ea > 360 || ($ea > 0 && $ea <= 90) ) { - if( $ea > 0 && $ea <= 90 ) { - // Adjust angle to simplify conditions in loops - $rea += 2*M_PI; - } - - $p = array($xc,$yc,$xc,$yc+$z, - $xc+$w*$cossa,$z+$yc-$h*$sinsa); - $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); - - for( $a=$rsa; $a < 2*M_PI; $a += $step ) { - $tca = cos($a); - $tsa = sin($a); - $p[] = $xc+$w*$tca; - $p[] = $z+$yc-$h*$tsa; - $pt[] = $xc+$w*$tca; - $pt[] = $yc-$h*$tsa; - } - - $pt[] = $xc+$w; - $pt[] = $yc; - - $p[] = $xc+$w; - $p[] = $z+$yc; - $p[] = $xc+$w; - $p[] = $yc; - $p[] = $xc; - $p[] = $yc; - - for( $a=2*M_PI+$step; $a < $rea; $a += $step ) { - $pt[] = $xc + $w*cos($a); - $pt[] = $yc - $h*sin($a); - } - - $pt[] = $xc+$w*$cosea; - $pt[] = $yc-$h*$sinea; - $pt[] = $xc; - $pt[] = $yc; - - } - else { - $p = array($xc,$yc,$xc,$yc+$z, - $xc+$w*$cossa,$z+$yc-$h*$sinsa); - $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); - - $rea = $rea == 0.0 ? 2*M_PI : $rea; - for( $a=$rsa; $a < $rea; $a += $step ) { - $tca = cos($a); - $tsa = sin($a); - $p[] = $xc+$w*$tca; - $p[] = $z+$yc-$h*$tsa; - $pt[] = $xc+$w*$tca; - $pt[] = $yc-$h*$tsa; - } - - $pt[] = $xc+$w*$cosea; - $pt[] = $yc-$h*$sinea; - $pt[] = $xc; - $pt[] = $yc; - - $p[] = $xc+$w*$cosea; - $p[] = $z+$yc-$h*$sinea; - $p[] = $xc+$w*$cosea; - $p[] = $yc-$h*$sinea; - $p[] = $xc; - $p[] = $yc; - } - } - elseif( $sa >= 180 ) { - $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); - $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); - - for( $a=$rea; $a>$rsa; $a -= $step ) { - $tca = cos($a); - $tsa = sin($a); - $p[] = $xc+$w*$tca; - $p[] = $z+$yc-$h*$tsa; - $pt[] = $xc+$w*$tca; - $pt[] = $yc-$h*$tsa; - } - - $pt[] = $xc+$w*$cossa; - $pt[] = $yc-$h*$sinsa; - $pt[] = $xc; - $pt[] = $yc; - - $p[] = $xc+$w*$cossa; - $p[] = $z+$yc-$h*$sinsa; - $p[] = $xc+$w*$cossa; - $p[] = $yc-$h*$sinsa; - $p[] = $xc; - $p[] = $yc; - - } - elseif( $sa >= 90 ) { - if( $ea > 180 ) { - $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); - $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); - - for( $a=$rea; $a > M_PI; $a -= $step ) { - $tca = cos($a); - $tsa = sin($a); - $p[] = $xc+$w*$tca; - $p[] = $z + $yc - $h*$tsa; - $pt[] = $xc+$w*$tca; - $pt[] = $yc-$h*$tsa; - } - - $p[] = $xc-$w; - $p[] = $z+$yc; - $p[] = $xc-$w; - $p[] = $yc; - $p[] = $xc; - $p[] = $yc; - - $pt[] = $xc-$w; - $pt[] = $z+$yc; - $pt[] = $xc-$w; - $pt[] = $yc; - - for( $a=M_PI-$step; $a > $rsa; $a -= $step ) { - $pt[] = $xc + $w*cos($a); - $pt[] = $yc - $h*sin($a); - } - - $pt[] = $xc+$w*$cossa; - $pt[] = $yc-$h*$sinsa; - $pt[] = $xc; - $pt[] = $yc; - - } - else { // $sa >= 90 && $ea <= 180 - $p = array($xc,$yc,$xc,$yc+$z, - $xc+$w*$cosea,$z+$yc-$h*$sinea, - $xc+$w*$cosea,$yc-$h*$sinea, - $xc,$yc); - - $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); - - for( $a=$rea; $a>$rsa; $a -= $step ) { - $pt[] = $xc + $w*cos($a); - $pt[] = $yc - $h*sin($a); - } - - $pt[] = $xc+$w*$cossa; - $pt[] = $yc-$h*$sinsa; - $pt[] = $xc; - $pt[] = $yc; - - } - } - else { // sa > 0 && ea < 90 - - $p = array($xc,$yc,$xc,$yc+$z, - $xc+$w*$cossa,$z+$yc-$h*$sinsa, - $xc+$w*$cossa,$yc-$h*$sinsa, - $xc,$yc); - - $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); - - for( $a=$rsa; $a < $rea; $a += $step ) { - $pt[] = $xc + $w*cos($a); - $pt[] = $yc - $h*sin($a); - } - - $pt[] = $xc+$w*$cosea; - $pt[] = $yc-$h*$sinea; - $pt[] = $xc; - $pt[] = $yc; - } - - $img->PushColor($fillcolor.":".$shadow); - $img->FilledPolygon($p); - $img->PopColor(); - - $img->PushColor($fillcolor); - $img->FilledPolygon($pt); - $img->PopColor(); - } - - function SetStartAngle($aStart) { - if( $aStart < 0 || $aStart > 360 ) { - JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.'); - } - $this->startangle = $aStart; - } - - // Draw a 3D Pie - function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z, - $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) { - - //--------------------------------------------------------------------------- - // As usual the algorithm get more complicated than I originally - // envisioned. I believe that this is as simple as it is possible - // to do it with the features I want. It's a good exercise to start - // thinking on how to do this to convince your self that all this - // is really needed for the general case. - // - // The algorithm two draw 3D pies without "real 3D" is done in - // two steps. - // First imagine the pie cut in half through a thought line between - // 12'a clock and 6'a clock. It now easy to imagine that we can plot - // the individual slices for each half by starting with the topmost - // pie slice and continue down to 6'a clock. - // - // In the algortithm this is done in three principal steps - // Step 1. Do the knife cut to ensure by splitting slices that extends - // over the cut line. This is done by splitting the original slices into - // upto 3 subslices. - // Step 2. Find the top slice for each half - // Step 3. Draw the slices from top to bottom - // - // The thing that slightly complicates this scheme with all the - // angle comparisons below is that we can have an arbitrary start - // angle so we must take into account the different equivalence classes. - // For the same reason we must walk through the angle array in a - // modulo fashion. - // - // Limitations of algorithm: - // * A small exploded slice which crosses the 270 degree point - // will get slightly nagged close to the center due to the fact that - // we print the slices in Z-order and that the slice left part - // get printed first and might get slightly nagged by a larger - // slice on the right side just before the right part of the small - // slice. Not a major problem though. - //--------------------------------------------------------------------------- - - - // Determine the height of the ellippse which gives an - // indication of the inclination angle - $h = ($angle/90.0)*$d; - $sum = 0; - for($i=0; $ilabeltype == 2 ) { - $this->adjusted_data = $this->AdjPercentage($data); - } - - // Setup the start - $accsum = 0; - $a = $startangle; - $a = $this->NormAngle($a); - - // - // Step 1 . Split all slices that crosses 90 or 270 - // - $idx=0; - $adjexplode=array(); - $numcolors = count($colors); - for($i=0; $iexplode_radius[$i]) ) { - $this->explode_radius[$i]=0; - } - - $expscale=1; - if( $aaoption == 1 ) { - $expscale=2; - } - - $la = $a + $da/2; - $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale, - $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale ); - $adjexplode[$idx] = $explode; - $labeldata[$i] = array($la,$explode[0],$explode[1]); - $originalangles[$i] = array($a,$a+$da); - - $ne = $this->NormAngle($a+$da); - if( $da <= 180 ) { - // If the slice size is <= 90 it can at maximum cut across - // one boundary (either 90 or 270) where it needs to be split - $split=-1; // no split - if( ($da<=90 && ($a <= 90 && $ne > 90)) || - (($da <= 180 && $da >90) && (($a < 90 || $a >= 270) && $ne > 90)) ) { - $split = 90; - } - elseif( ($da<=90 && ($a <= 270 && $ne > 270)) || - (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) { - $split = 270; - } - if( $split > 0 ) { // split in two - $angles[$idx] = array($a,$split); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - $angles[++$idx] = array($split,$ne); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - } - else { // no split - $angles[$idx] = array($a,$ne); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - } - } - else { - // da>180 - // Slice may, depending on position, cross one or two - // bonudaries - - if( $a < 90 ) $split = 90; - elseif( $a <= 270 ) $split = 270; - else $split = 90; - - $angles[$idx] = array($a,$split); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - //if( $a+$da > 360-$split ) { - // For slices larger than 270 degrees we might cross - // another boundary as well. This means that we must - // split the slice further. The comparison gets a little - // bit complicated since we must take into accound that - // a pie might have a startangle >0 and hence a slice might - // wrap around the 0 angle. - // Three cases: - // a) Slice starts before 90 and hence gets a split=90, but - // we must also check if we need to split at 270 - // b) Slice starts after 90 but before 270 and slices - // crosses 90 (after a wrap around of 0) - // c) If start is > 270 (hence the firstr split is at 90) - // and the slice is so large that it goes all the way - // around 270. - if( ($a < 90 && ($a+$da > 270)) || ($a > 90 && $a<=270 && ($a+$da>360+90) ) || ($a > 270 && $this->NormAngle($a+$da)>270) ) { - $angles[++$idx] = array($split,360-$split); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - $angles[++$idx] = array(360-$split,$ne); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - } - else { - // Just a simple split to the previous decided - // angle. - $angles[++$idx] = array($split,$ne); - $adjcolors[$idx] = $colors[$i % $numcolors]; - $adjexplode[$idx] = $explode; - } - } - $a += $da; - $a = $this->NormAngle($a); - } - - // Total number of slices - $n = count($angles); - - for($i=0; $i<$n; ++$i) { - list($dbgs,$dbge) = $angles[$i]; - } - - // - // Step 2. Find start index (first pie that starts in upper left quadrant) - // - $minval = $angles[0][0]; - $min = 0; - for( $i=0; $i<$n; ++$i ) { - if( $angles[$i][0] < $minval ) { - $minval = $angles[$i][0]; - $min = $i; - } - } - $j = $min; - $cnt = 0; - while( $angles[$j][1] <= 90 ) { - $j++; - if( $j>=$n) { - $j=0; - } - if( $cnt > $n ) { - JpGraphError::RaiseL(14005); - //("Pie3D Internal error (#1). Trying to wrap twice when looking for start index"); - } - ++$cnt; - } - $start = $j; - - // - // Step 3. Print slices in z-order - // - $cnt = 0; - - // First stroke all the slices between 90 and 270 (left half circle) - // counterclockwise - - while( $angles[$j][0] < 270 && $aaoption !== 2 ) { - - list($x,$y) = $adjexplode[$j]; - - $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], - $z,$adjcolors[$j],$shadow); - - $last = array($x,$y,$j); - - $j++; - if( $j >= $n ) $j=0; - if( $cnt > $n ) { - JpGraphError::RaiseL(14006); - //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); - } - ++$cnt; - } - - $slice_left = $n-$cnt; - $j=$start-1; - if($j<0) $j=$n-1; - $cnt = 0; - - // The stroke all slices from 90 to -90 (right half circle) - // clockwise - while( $cnt < $slice_left && $aaoption !== 2 ) { - - list($x,$y) = $adjexplode[$j]; - - $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], - $z,$adjcolors[$j],$shadow); - $j--; - if( $cnt > $n ) { - JpGraphError::RaiseL(14006); - //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); - } - if($j<0) $j=$n-1; - $cnt++; - } - - // Now do a special thing. Stroke the last slice on the left - // halfcircle one more time. This is needed in the case where - // the slice close to 270 have been exploded. In that case the - // part of the slice close to the center of the pie might be - // slightly nagged. - if( $aaoption !== 2 ) - $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0], - $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow); - - - if( $aaoption !== 1 ) { - // Now print possible labels and add csim - $this->value->ApplyFont($img); - $margin = $img->GetFontHeight()/2 + $this->value->margin ; - for($i=0; $i < count($data); ++$i ) { - $la = $labeldata[$i][0]; - $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin)*$this->ilabelposadj; - $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin)*$this->ilabelposadj; - if( $this->ilabelposadj >= 1.0 ) { - if( $la > 180 && $la < 360 ) $y += $z; - } - if( $this->labeltype == 0 ) { - if( $sum > 0 ) $l = 100*$data[$i]/$sum; - else $l = 0; - } - elseif( $this->labeltype == 1 ) { - $l = $data[$i]; - } - else { - $l = $this->adjusted_data[$i]; - } - if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) { - $l=sprintf($this->labels[$i],$l); - } - - $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z); - - $this->Add3DSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z, - $originalangles[$i][0],$originalangles[$i][1]); - } - } - - // - // Finally add potential lines in pie - // - - if( $edgecolor=="" || $aaoption !== 0 ) return; - - $accsum = 0; - $a = $startangle; - $a = $this->NormAngle($a); - - $a *= M_PI/180.0; - - $idx=0; - $img->PushColor($edgecolor); - $img->SetLineWeight($edgeweight); - - $fulledge = true; - for($i=0; $i < count($data) && $fulledge; ++$i ) { - if( empty($this->explode_radius[$i]) ) { - $this->explode_radius[$i]=0; - } - if( $this->explode_radius[$i] > 0 ) { - $fulledge = false; - } - } - - - for($i=0; $i < count($data); ++$i, ++$idx ) { - - $da = $data[$i]/$sum * 2*M_PI; - $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor, - $this->explode_radius[$i],$fulledge); - $a += $da; - } - $img->PopColor(); - } - - function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) { - $step = 0.02; - - if( $exploderadius > 0 ) { - $la = ($sa+$ea)/2; - $xc += $exploderadius*cos($la); - $yc -= $exploderadius*sin($la) * ($h/$w) ; - - } - - $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa)); - - for($a=$sa; $a < $ea; $a += $step ) { - $p[] = $xc + $w*cos($a); - $p[] = $yc - $h*sin($a); - } - - $p[] = $xc+$w*cos($ea); - $p[] = $yc-$h*sin($ea); - $p[] = $xc; - $p[] = $yc; - - $img->SetColor($edgecolor); - $img->Polygon($p); - - // Unfortunately we can't really draw the full edge around the whole of - // of the slice if any of the slices are exploded. The reason is that - // this algorithm is to simply. There are cases where the edges will - // "overwrite" other slices when they have been exploded. - // Doing the full, proper 3D hidden lines stiff is actually quite - // tricky. So for exploded pies we only draw the top edge. Not perfect - // but the "real" solution is much more complicated. - if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) { - - if($sa < M_PI && $ea > M_PI) { - $sa = M_PI; - } - - if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) ) { - $ea = 2*M_PI; - } - - if( $sa >= M_PI && $ea <= 2*M_PI ) { - $p = array($xc + $w*cos($sa),$yc - $h*sin($sa), - $xc + $w*cos($sa),$z + $yc - $h*sin($sa)); - - for($a=$sa+$step; $a < $ea; $a += $step ) { - $p[] = $xc + $w*cos($a); - $p[] = $z + $yc - $h*sin($a); - } - $p[] = $xc + $w*cos($ea); - $p[] = $z + $yc - $h*sin($ea); - $p[] = $xc + $w*cos($ea); - $p[] = $yc - $h*sin($ea); - $img->SetColor($edgecolor); - $img->Polygon($p); - } - } - } - - function Stroke($img,$aaoption=0) { - $n = count($this->data); - - // If user hasn't set the colors use the theme array - if( $this->setslicecolors==null ) { - $colors = array_keys($img->rgb->rgb_table); - sort($colors); - $idx_a=$this->themearr[$this->theme]; - $ca = array(); - $m = count($idx_a); - for($i=0; $i < $m; ++$i) { - $ca[$i] = $colors[$idx_a[$i]]; - } - $ca = array_reverse(array_slice($ca,0,$n)); - } - else { - $ca = $this->setslicecolors; - } - - - if( $this->posx <= 1 && $this->posx > 0 ) { - $xc = round($this->posx*$img->width); - } - else { - $xc = $this->posx ; - } - - if( $this->posy <= 1 && $this->posy > 0 ) { - $yc = round($this->posy*$img->height); - } - else { - $yc = $this->posy ; - } - - if( $this->radius <= 1 ) { - $width = floor($this->radius*min($img->width,$img->height)); - // Make sure that the pie doesn't overflow the image border - // The 0.9 factor is simply an extra margin to leave some space - // between the pie an the border of the image. - $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9)); - } - else { - $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ; - } - - // Add a sanity check for width - if( $width < 1 ) { - JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0"); - } - - // Establish a thickness. By default the thickness is a fifth of the - // pie slice width (=pie radius) but since the perspective depends - // on the inclination angle we use some heuristics to make the edge - // slightly thicker the less the angle. - - // Has user specified an absolute thickness? In that case use - // that instead - - if( $this->iThickness ) { - $thick = $this->iThickness; - $thick *= ($aaoption === 1 ? 2 : 1 ); - } - else { - $thick = $width/12; - } - $a = $this->angle; - - if( $a <= 30 ) $thick *= 1.6; - elseif( $a <= 40 ) $thick *= 1.4; - elseif( $a <= 50 ) $thick *= 1.2; - elseif( $a <= 60 ) $thick *= 1.0; - elseif( $a <= 70 ) $thick *= 0.8; - elseif( $a <= 80 ) $thick *= 0.7; - else $thick *= 0.6; - - $thick = floor($thick); - - if( $this->explode_all ) { - for($i=0; $i < $n; ++$i) - $this->explode_radius[$i]=$this->explode_r; - } - - $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle, - $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight); - - // Adjust title position - if( $aaoption != 1 ) { - $this->title->SetPos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin, "center","bottom"); - $this->title->Stroke($img); - } - } - - //--------------- - // PRIVATE METHODS - - // Position the labels of each slice - function StrokeLabels($label,$img,$a,$xp,$yp,$z) { - $this->value->halign="left"; - $this->value->valign="top"; - - // Position the axis title. - // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text - // that intersects with the extension of the corresponding axis. The code looks a little - // bit messy but this is really the only way of having a reasonable position of the - // axis titles. - $this->value->ApplyFont($img); - $h=$img->GetTextHeight($label); - // For numeric values the format of the display value - // must be taken into account - if( is_numeric($label) ) { - if( $label >= 0 ) { - $w=$img->GetTextWidth(sprintf($this->value->format,$label)); - } - else { - $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); - } - } - else { - $w=$img->GetTextWidth($label); - } - - while( $a > 2*M_PI ) { - $a -= 2*M_PI; - } - - if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; - if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; - if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; - if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); - - if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; - if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); - if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; - if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); - if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; - - $x = round($xp-$dx*$w); - $y = round($yp-$dy*$h); - - // Mark anchor point for debugging - /* - $img->SetColor('red'); - $img->Line($xp-10,$yp,$xp+10,$yp); - $img->Line($xp,$yp-10,$xp,$yp+10); - */ - - $oldmargin = $this->value->margin; - $this->value->margin=0; - $this->value->Stroke($img,$label,$x,$y); - $this->value->margin=$oldmargin; - - } -} // Class - -/* EOF */ -?> +radius = 0.5; + $this->data = $data; + $this->title = new Text(""); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->value = new DisplayValue(); + $this->value->Show(); + $this->value->SetFormat('%.0f%%'); + } + + //--------------- + // PUBLIC METHODS + + // Set label arrays + function SetLegends($aLegend) { + $this->legends = array_reverse(array_slice($aLegend,0,count($this->data))); + } + + function SetSliceColors($aColors) { + $this->setslicecolors = $aColors; + } + + function Legend($aGraph) { + parent::Legend($aGraph); + $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol); + } + + function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { + $this->csimtargets = $aTargets; + $this->csimwintargets = $aWinTargets; + $this->csimalts = $aAlts; + } + + // Should the slices be separated by a line? If color is specified as "" no line + // will be used to separate pie slices. + function SetEdge($aColor='black',$aWeight=1) { + $this->edgecolor = $aColor; + $this->edgeweight = $aWeight; + } + + // Specify projection angle for 3D in degrees + // Must be between 20 and 70 degrees + function SetAngle($a) { + if( $a<5 || $a>90 ) { + JpGraphError::RaiseL(14002); + //("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees."); + } + else { + $this->angle = $a; + } + } + + function Add3DSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle + + $sa *= M_PI/180; + $ea *= M_PI/180; + + //add coordinates of the centre to the map + $coords = "$xc, $yc"; + + //add coordinates of the first point on the arc to the map + $xp = floor($width*cos($sa)/2+$xc); + $yp = floor($yc-$height*sin($sa)/2); + $coords.= ", $xp, $yp"; + + //If on the front half, add the thickness offset + if ($sa >= M_PI && $sa <= 2*M_PI*1.01) { + $yp = floor($yp+$thick); + $coords.= ", $xp, $yp"; + } + + //add coordinates every 0.2 radians + $a=$sa+0.2; + while ($a<$ea) { + $xp = floor($width*cos($a)/2+$xc); + if ($a >= M_PI && $a <= 2*M_PI*1.01) { + $yp = floor($yc-($height*sin($a)/2)+$thick); + } else { + $yp = floor($yc-$height*sin($a)/2); + } + $coords.= ", $xp, $yp"; + $a += 0.2; + } + + //Add the last point on the arc + $xp = floor($width*cos($ea)/2+$xc); + $yp = floor($yc-$height*sin($ea)/2); + + + if ($ea >= M_PI && $ea <= 2*M_PI*1.01) { + $coords.= ", $xp, ".floor($yp+$thick); + } + $coords.= ", $xp, $yp"; + $alt=''; + + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= "csimtargets[$i]."\""; + + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + + if( !empty($this->csimalts[$i]) ) { + $tmp=sprintf($this->csimalts[$i],$this->data[$i]); + $this->csimareas .= "alt=\"$tmp\" title=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + + } + + function SetLabels($aLabels,$aLblPosAdj="auto") { + $this->labels = $aLabels; + $this->ilabelposadj=$aLblPosAdj; + } + + + // Distance from the pie to the labels + function SetLabelMargin($m) { + $this->value->SetMargin($m); + } + + // Show a thin line from the pie to the label for a specific slice + function ShowLabelHint($f=true) { + $this->showlabelhint=$f; + } + + // Set color of hint line to label for each slice + function SetLabelHintColor($c) { + $this->labelhintcolor=$c; + } + + function SetHeight($aHeight) { + $this->iThickness = $aHeight; + } + + + // Normalize Angle between 0-360 + function NormAngle($a) { + // Normalize anle to 0 to 2M_PI + // + if( $a > 0 ) { + while($a > 360) $a -= 360; + } + else { + while($a < 0) $a += 360; + } + if( $a < 0 ) + $a = 360 + $a; + + if( $a == 360 ) $a=0; + return $a; + } + + + + // Draw one 3D pie slice at position ($xc,$yc) with height $z + function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) { + + // Due to the way the 3D Pie algorithm works we are + // guaranteed that any slice we get into this method + // belongs to either the left or right side of the + // pie ellipse. Hence, no slice will cross 90 or 270 + // point. + if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) { + JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice'); + exit(1); + } + + $p[] = array(); + + // Setup pre-calculated values + $rsa = $sa/180*M_PI; // to Rad + $rea = $ea/180*M_PI; // to Rad + $sinsa = sin($rsa); + $cossa = cos($rsa); + $sinea = sin($rea); + $cosea = cos($rea); + + // p[] is the points for the overall slice and + // pt[] is the points for the top pie + + // Angular step when approximating the arc with a polygon train. + $step = 0.05; + + if( $sa >= 270 ) { + if( $ea > 360 || ($ea > 0 && $ea <= 90) ) { + if( $ea > 0 && $ea <= 90 ) { + // Adjust angle to simplify conditions in loops + $rea += 2*M_PI; + } + + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cossa,$z+$yc-$h*$sinsa); + $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); + + for( $a=$rsa; $a < 2*M_PI; $a += $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z+$yc-$h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $pt[] = $xc+$w; + $pt[] = $yc; + + $p[] = $xc+$w; + $p[] = $z+$yc; + $p[] = $xc+$w; + $p[] = $yc; + $p[] = $xc; + $p[] = $yc; + + for( $a=2*M_PI+$step; $a < $rea; $a += $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cosea; + $pt[] = $yc-$h*$sinea; + $pt[] = $xc; + $pt[] = $yc; + + } + else { + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cossa,$z+$yc-$h*$sinsa); + $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); + + $rea = $rea == 0.0 ? 2*M_PI : $rea; + for( $a=$rsa; $a < $rea; $a += $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z+$yc-$h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $pt[] = $xc+$w*$cosea; + $pt[] = $yc-$h*$sinea; + $pt[] = $xc; + $pt[] = $yc; + + $p[] = $xc+$w*$cosea; + $p[] = $z+$yc-$h*$sinea; + $p[] = $xc+$w*$cosea; + $p[] = $yc-$h*$sinea; + $p[] = $xc; + $p[] = $yc; + } + } + elseif( $sa >= 180 ) { + $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); + $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); + + for( $a=$rea; $a>$rsa; $a -= $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z+$yc-$h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $pt[] = $xc+$w*$cossa; + $pt[] = $yc-$h*$sinsa; + $pt[] = $xc; + $pt[] = $yc; + + $p[] = $xc+$w*$cossa; + $p[] = $z+$yc-$h*$sinsa; + $p[] = $xc+$w*$cossa; + $p[] = $yc-$h*$sinsa; + $p[] = $xc; + $p[] = $yc; + + } + elseif( $sa >= 90 ) { + if( $ea > 180 ) { + $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); + $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); + + for( $a=$rea; $a > M_PI; $a -= $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z + $yc - $h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $p[] = $xc-$w; + $p[] = $z+$yc; + $p[] = $xc-$w; + $p[] = $yc; + $p[] = $xc; + $p[] = $yc; + + $pt[] = $xc-$w; + $pt[] = $z+$yc; + $pt[] = $xc-$w; + $pt[] = $yc; + + for( $a=M_PI-$step; $a > $rsa; $a -= $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cossa; + $pt[] = $yc-$h*$sinsa; + $pt[] = $xc; + $pt[] = $yc; + + } + else { // $sa >= 90 && $ea <= 180 + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cosea,$z+$yc-$h*$sinea, + $xc+$w*$cosea,$yc-$h*$sinea, + $xc,$yc); + + $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); + + for( $a=$rea; $a>$rsa; $a -= $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cossa; + $pt[] = $yc-$h*$sinsa; + $pt[] = $xc; + $pt[] = $yc; + + } + } + else { // sa > 0 && ea < 90 + + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cossa,$z+$yc-$h*$sinsa, + $xc+$w*$cossa,$yc-$h*$sinsa, + $xc,$yc); + + $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); + + for( $a=$rsa; $a < $rea; $a += $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cosea; + $pt[] = $yc-$h*$sinea; + $pt[] = $xc; + $pt[] = $yc; + } + + $img->PushColor($fillcolor.":".$shadow); + $img->FilledPolygon($p); + $img->PopColor(); + + $img->PushColor($fillcolor); + $img->FilledPolygon($pt); + $img->PopColor(); + } + + function SetStartAngle($aStart) { + if( $aStart < 0 || $aStart > 360 ) { + JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.'); + } + $this->startangle = $aStart; + } + + // Draw a 3D Pie + function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z, + $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) { + + //--------------------------------------------------------------------------- + // As usual the algorithm get more complicated than I originally + // envisioned. I believe that this is as simple as it is possible + // to do it with the features I want. It's a good exercise to start + // thinking on how to do this to convince your self that all this + // is really needed for the general case. + // + // The algorithm two draw 3D pies without "real 3D" is done in + // two steps. + // First imagine the pie cut in half through a thought line between + // 12'a clock and 6'a clock. It now easy to imagine that we can plot + // the individual slices for each half by starting with the topmost + // pie slice and continue down to 6'a clock. + // + // In the algortithm this is done in three principal steps + // Step 1. Do the knife cut to ensure by splitting slices that extends + // over the cut line. This is done by splitting the original slices into + // upto 3 subslices. + // Step 2. Find the top slice for each half + // Step 3. Draw the slices from top to bottom + // + // The thing that slightly complicates this scheme with all the + // angle comparisons below is that we can have an arbitrary start + // angle so we must take into account the different equivalence classes. + // For the same reason we must walk through the angle array in a + // modulo fashion. + // + // Limitations of algorithm: + // * A small exploded slice which crosses the 270 degree point + // will get slightly nagged close to the center due to the fact that + // we print the slices in Z-order and that the slice left part + // get printed first and might get slightly nagged by a larger + // slice on the right side just before the right part of the small + // slice. Not a major problem though. + //--------------------------------------------------------------------------- + + + // Determine the height of the ellippse which gives an + // indication of the inclination angle + $h = ($angle/90.0)*$d; + $sum = 0; + for($i=0; $ilabeltype == 2 ) { + $this->adjusted_data = $this->AdjPercentage($data); + } + + // Setup the start + $accsum = 0; + $a = $startangle; + $a = $this->NormAngle($a); + + // + // Step 1 . Split all slices that crosses 90 or 270 + // + $idx=0; + $adjexplode=array(); + $numcolors = count($colors); + for($i=0; $iexplode_radius[$i]) ) { + $this->explode_radius[$i]=0; + } + + $expscale=1; + if( $aaoption == 1 ) { + $expscale=2; + } + + $la = $a + $da/2; + $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale, + $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale ); + $adjexplode[$idx] = $explode; + $labeldata[$i] = array($la,$explode[0],$explode[1]); + $originalangles[$i] = array($a,$a+$da); + + $ne = $this->NormAngle($a+$da); + if( $da <= 180 ) { + // If the slice size is <= 90 it can at maximum cut across + // one boundary (either 90 or 270) where it needs to be split + $split=-1; // no split + if( ($da<=90 && ($a <= 90 && $ne > 90)) || + (($da <= 180 && $da >90) && (($a < 90 || $a >= 270) && $ne > 90)) ) { + $split = 90; + } + elseif( ($da<=90 && ($a <= 270 && $ne > 270)) || + (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) { + $split = 270; + } + if( $split > 0 ) { // split in two + $angles[$idx] = array($a,$split); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + $angles[++$idx] = array($split,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + else { // no split + $angles[$idx] = array($a,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + } + else { + // da>180 + // Slice may, depending on position, cross one or two + // bonudaries + + if( $a < 90 ) $split = 90; + elseif( $a <= 270 ) $split = 270; + else $split = 90; + + $angles[$idx] = array($a,$split); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + //if( $a+$da > 360-$split ) { + // For slices larger than 270 degrees we might cross + // another boundary as well. This means that we must + // split the slice further. The comparison gets a little + // bit complicated since we must take into accound that + // a pie might have a startangle >0 and hence a slice might + // wrap around the 0 angle. + // Three cases: + // a) Slice starts before 90 and hence gets a split=90, but + // we must also check if we need to split at 270 + // b) Slice starts after 90 but before 270 and slices + // crosses 90 (after a wrap around of 0) + // c) If start is > 270 (hence the firstr split is at 90) + // and the slice is so large that it goes all the way + // around 270. + if( ($a < 90 && ($a+$da > 270)) || ($a > 90 && $a<=270 && ($a+$da>360+90) ) || ($a > 270 && $this->NormAngle($a+$da)>270) ) { + $angles[++$idx] = array($split,360-$split); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + $angles[++$idx] = array(360-$split,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + else { + // Just a simple split to the previous decided + // angle. + $angles[++$idx] = array($split,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + } + $a += $da; + $a = $this->NormAngle($a); + } + + // Total number of slices + $n = count($angles); + + for($i=0; $i<$n; ++$i) { + list($dbgs,$dbge) = $angles[$i]; + } + + // + // Step 2. Find start index (first pie that starts in upper left quadrant) + // + $minval = $angles[0][0]; + $min = 0; + for( $i=0; $i<$n; ++$i ) { + if( $angles[$i][0] < $minval ) { + $minval = $angles[$i][0]; + $min = $i; + } + } + $j = $min; + $cnt = 0; + while( $angles[$j][1] <= 90 ) { + $j++; + if( $j>=$n) { + $j=0; + } + if( $cnt > $n ) { + JpGraphError::RaiseL(14005); + //("Pie3D Internal error (#1). Trying to wrap twice when looking for start index"); + } + ++$cnt; + } + $start = $j; + + // + // Step 3. Print slices in z-order + // + $cnt = 0; + + // First stroke all the slices between 90 and 270 (left half circle) + // counterclockwise + + while( $angles[$j][0] < 270 && $aaoption !== 2 ) { + + list($x,$y) = $adjexplode[$j]; + + $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], + $z,$adjcolors[$j],$shadow); + + $last = array($x,$y,$j); + + $j++; + if( $j >= $n ) $j=0; + if( $cnt > $n ) { + JpGraphError::RaiseL(14006); + //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); + } + ++$cnt; + } + + $slice_left = $n-$cnt; + $j=$start-1; + if($j<0) $j=$n-1; + $cnt = 0; + + // The stroke all slices from 90 to -90 (right half circle) + // clockwise + while( $cnt < $slice_left && $aaoption !== 2 ) { + + list($x,$y) = $adjexplode[$j]; + + $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], + $z,$adjcolors[$j],$shadow); + $j--; + if( $cnt > $n ) { + JpGraphError::RaiseL(14006); + //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); + } + if($j<0) $j=$n-1; + $cnt++; + } + + // Now do a special thing. Stroke the last slice on the left + // halfcircle one more time. This is needed in the case where + // the slice close to 270 have been exploded. In that case the + // part of the slice close to the center of the pie might be + // slightly nagged. + if( $aaoption !== 2 ) + $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0], + $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow); + + + if( $aaoption !== 1 ) { + // Now print possible labels and add csim + $this->value->ApplyFont($img); + $margin = $img->GetFontHeight()/2 + $this->value->margin ; + for($i=0; $i < count($data); ++$i ) { + $la = $labeldata[$i][0]; + $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin)*$this->ilabelposadj; + $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin)*$this->ilabelposadj; + if( $this->ilabelposadj >= 1.0 ) { + if( $la > 180 && $la < 360 ) $y += $z; + } + if( $this->labeltype == 0 ) { + if( $sum > 0 ) $l = 100*$data[$i]/$sum; + else $l = 0; + } + elseif( $this->labeltype == 1 ) { + $l = $data[$i]; + } + else { + $l = $this->adjusted_data[$i]; + } + if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) { + $l=sprintf($this->labels[$i],$l); + } + + $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z); + + $this->Add3DSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z, + $originalangles[$i][0],$originalangles[$i][1]); + } + } + + // + // Finally add potential lines in pie + // + + if( $edgecolor=="" || $aaoption !== 0 ) return; + + $accsum = 0; + $a = $startangle; + $a = $this->NormAngle($a); + + $a *= M_PI/180.0; + + $idx=0; + $img->PushColor($edgecolor); + $img->SetLineWeight($edgeweight); + + $fulledge = true; + for($i=0; $i < count($data) && $fulledge; ++$i ) { + if( empty($this->explode_radius[$i]) ) { + $this->explode_radius[$i]=0; + } + if( $this->explode_radius[$i] > 0 ) { + $fulledge = false; + } + } + + + for($i=0; $i < count($data); ++$i, ++$idx ) { + + $da = $data[$i]/$sum * 2*M_PI; + $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor, + $this->explode_radius[$i],$fulledge); + $a += $da; + } + $img->PopColor(); + } + + function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) { + $step = 0.02; + + if( $exploderadius > 0 ) { + $la = ($sa+$ea)/2; + $xc += $exploderadius*cos($la); + $yc -= $exploderadius*sin($la) * ($h/$w) ; + + } + + $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa)); + + for($a=$sa; $a < $ea; $a += $step ) { + $p[] = $xc + $w*cos($a); + $p[] = $yc - $h*sin($a); + } + + $p[] = $xc+$w*cos($ea); + $p[] = $yc-$h*sin($ea); + $p[] = $xc; + $p[] = $yc; + + $img->SetColor($edgecolor); + $img->Polygon($p); + + // Unfortunately we can't really draw the full edge around the whole of + // of the slice if any of the slices are exploded. The reason is that + // this algorithm is to simply. There are cases where the edges will + // "overwrite" other slices when they have been exploded. + // Doing the full, proper 3D hidden lines stiff is actually quite + // tricky. So for exploded pies we only draw the top edge. Not perfect + // but the "real" solution is much more complicated. + if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) { + + if($sa < M_PI && $ea > M_PI) { + $sa = M_PI; + } + + if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) ) { + $ea = 2*M_PI; + } + + if( $sa >= M_PI && $ea <= 2*M_PI ) { + $p = array($xc + $w*cos($sa),$yc - $h*sin($sa), + $xc + $w*cos($sa),$z + $yc - $h*sin($sa)); + + for($a=$sa+$step; $a < $ea; $a += $step ) { + $p[] = $xc + $w*cos($a); + $p[] = $z + $yc - $h*sin($a); + } + $p[] = $xc + $w*cos($ea); + $p[] = $z + $yc - $h*sin($ea); + $p[] = $xc + $w*cos($ea); + $p[] = $yc - $h*sin($ea); + $img->SetColor($edgecolor); + $img->Polygon($p); + } + } + } + + function Stroke($img,$aaoption=0) { + $n = count($this->data); + + // If user hasn't set the colors use the theme array + if( $this->setslicecolors==null ) { + $colors = array_keys($img->rgb->rgb_table); + sort($colors); + $idx_a=$this->themearr[$this->theme]; + $ca = array(); + $m = count($idx_a); + for($i=0; $i < $m; ++$i) { + $ca[$i] = $colors[$idx_a[$i]]; + } + $ca = array_reverse(array_slice($ca,0,$n)); + } + else { + $ca = $this->setslicecolors; + } + + + if( $this->posx <= 1 && $this->posx > 0 ) { + $xc = round($this->posx*$img->width); + } + else { + $xc = $this->posx ; + } + + if( $this->posy <= 1 && $this->posy > 0 ) { + $yc = round($this->posy*$img->height); + } + else { + $yc = $this->posy ; + } + + if( $this->radius <= 1 ) { + $width = floor($this->radius*min($img->width,$img->height)); + // Make sure that the pie doesn't overflow the image border + // The 0.9 factor is simply an extra margin to leave some space + // between the pie an the border of the image. + $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9)); + } + else { + $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ; + } + + // Add a sanity check for width + if( $width < 1 ) { + JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0"); + } + + // Establish a thickness. By default the thickness is a fifth of the + // pie slice width (=pie radius) but since the perspective depends + // on the inclination angle we use some heuristics to make the edge + // slightly thicker the less the angle. + + // Has user specified an absolute thickness? In that case use + // that instead + + if( $this->iThickness ) { + $thick = $this->iThickness; + $thick *= ($aaoption === 1 ? 2 : 1 ); + } + else { + $thick = $width/12; + } + $a = $this->angle; + + if( $a <= 30 ) $thick *= 1.6; + elseif( $a <= 40 ) $thick *= 1.4; + elseif( $a <= 50 ) $thick *= 1.2; + elseif( $a <= 60 ) $thick *= 1.0; + elseif( $a <= 70 ) $thick *= 0.8; + elseif( $a <= 80 ) $thick *= 0.7; + else $thick *= 0.6; + + $thick = floor($thick); + + if( $this->explode_all ) { + for($i=0; $i < $n; ++$i) + $this->explode_radius[$i]=$this->explode_r; + } + + $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle, + $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight); + + // Adjust title position + if( $aaoption != 1 ) { + $this->title->SetPos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin, "center","bottom"); + $this->title->Stroke($img); + } + } + + //--------------- + // PRIVATE METHODS + + // Position the labels of each slice + function StrokeLabels($label,$img,$a,$xp,$yp,$z) { + $this->value->halign="left"; + $this->value->valign="top"; + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + $this->value->ApplyFont($img); + $h=$img->GetTextHeight($label); + // For numeric values the format of the display value + // must be taken into account + if( is_numeric($label) ) { + if( $label >= 0 ) { + $w=$img->GetTextWidth(sprintf($this->value->format,$label)); + } + else { + $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); + } + } + else { + $w=$img->GetTextWidth($label); + } + + while( $a > 2*M_PI ) { + $a -= 2*M_PI; + } + + if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); + + if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; + if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; + + $x = round($xp-$dx*$w); + $y = round($yp-$dy*$h); + + // Mark anchor point for debugging + /* + $img->SetColor('red'); + $img->Line($xp-10,$yp,$xp+10,$yp); + $img->Line($xp,$yp-10,$xp,$yp+10); + */ + + $oldmargin = $this->value->margin; + $this->value->margin=0; + $this->value->Stroke($img,$label,$x,$y); + $this->value->margin=$oldmargin; + + } +} // Class + +/* EOF */ +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_plotband.php b/ext/jpgraph-3.0.7/src/jpgraph_plotband.php index c58912e..485f65b 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_plotband.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_plotband.php @@ -1,635 +1,635 @@ -x=$aX; - $this->y=$aY; - $this->w=$aWidth; - $this->h=$aHeight; - $this->xe=$aX+$aWidth-1; - $this->ye=$aY+$aHeight-1; - } -} - -//===================================================================== -// Class RectPattern -// Base class for pattern hierarchi that is used to display patterned -// bands on the graph. Any subclass that doesn't override Stroke() -// must at least implement method DoPattern($aImg) which is responsible -// for drawing the pattern onto the graph. -//===================================================================== -class RectPattern { - protected $color; - protected $weight; - protected $rect=null; - protected $doframe=true; - protected $linespacing; // Line spacing in pixels - protected $iBackgroundColor=-1; // Default is no background fill - - function __construct($aColor,$aWeight=1) { - $this->color = $aColor; - $this->weight = $aWeight; - } - - function SetBackground($aBackgroundColor) { - $this->iBackgroundColor=$aBackgroundColor; - } - - function SetPos($aRect) { - $this->rect = $aRect; - } - - function ShowFrame($aShow=true) { - $this->doframe=$aShow; - } - - function SetDensity($aDens) { - if( $aDens < 1 || $aDens > 100 ) - JpGraphError::RaiseL(16001,$aDens); - //(" Desity for pattern must be between 1 and 100. (You tried $aDens)"); - // 1% corresponds to linespacing=50 - // 100 % corresponds to linespacing 1 - $this->linespacing = floor(((100-$aDens)/100.0)*50)+1; - - } - - function Stroke($aImg) { - if( $this->rect == null ) - JpGraphError::RaiseL(16002); - //(" No positions specified for pattern."); - - if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) { - $aImg->SetColor($this->iBackgroundColor); - $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); - } - - $aImg->SetColor($this->color); - $aImg->SetLineWeight($this->weight); - - // Virtual function implemented by subclass - $this->DoPattern($aImg); - - // Frame around the pattern area - if( $this->doframe ) - $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); - } - -} - - -//===================================================================== -// Class RectPatternSolid -// Implements a solid band -//===================================================================== -class RectPatternSolid extends RectPattern { - - function __construct($aColor="black",$aWeight=1) { - parent::__construct($aColor,$aWeight); - } - - function DoPattern($aImg) { - $aImg->SetColor($this->color); - $aImg->FilledRectangle($this->rect->x,$this->rect->y, - $this->rect->xe,$this->rect->ye); - } -} - -//===================================================================== -// Class RectPatternHor -// Implements horizontal line pattern -//===================================================================== -class RectPatternHor extends RectPattern { - - function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) { - parent::__construct($aColor,$aWeight); - $this->linespacing = $aLineSpacing; - } - - function DoPattern($aImg) { - $x0 = $this->rect->x; - $x1 = $this->rect->xe; - $y = $this->rect->y; - while( $y < $this->rect->ye ) { - $aImg->Line($x0,$y,$x1,$y); - $y += $this->linespacing; - } - } -} - -//===================================================================== -// Class RectPatternVert -// Implements vertical line pattern -//===================================================================== -class RectPatternVert extends RectPattern { - - function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) { - parent::__construct($aColor,$aWeight); - $this->linespacing = $aLineSpacing; - } - - //-------------------- - // Private methods - // - function DoPattern($aImg) { - $x = $this->rect->x; - $y0 = $this->rect->y; - $y1 = $this->rect->ye; - while( $x < $this->rect->xe ) { - $aImg->Line($x,$y0,$x,$y1); - $x += $this->linespacing; - } - } -} - - -//===================================================================== -// Class RectPatternRDiag -// Implements right diagonal pattern -//===================================================================== -class RectPatternRDiag extends RectPattern { - - function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) { - parent::__construct($aColor,$aWeight); - $this->linespacing = $aLineSpacing; - } - - function DoPattern($aImg) { - // -------------------- - // | / / / / /| - // |/ / / / / | - // | / / / / | - // -------------------- - $xe = $this->rect->xe; - $ye = $this->rect->ye; - $x0 = $this->rect->x + round($this->linespacing/2); - $y0 = $this->rect->y; - $x1 = $this->rect->x; - $y1 = $this->rect->y + round($this->linespacing/2); - - while($x0<=$xe && $y1<=$ye) { - $aImg->Line($x0,$y0,$x1,$y1); - $x0 += $this->linespacing; - $y1 += $this->linespacing; - } - - if( $xe-$x1 > $ye-$y0 ) { - // Width larger than height - $x1 = $this->rect->x + ($y1-$ye); - $y1 = $ye; - $y0 = $this->rect->y; - while( $x0 <= $xe ) { - $aImg->Line($x0,$y0,$x1,$y1); - $x0 += $this->linespacing; - $x1 += $this->linespacing; - } - - $y0=$this->rect->y + ($x0-$xe); - $x0=$xe; - } - else { - // Height larger than width - $diff = $x0-$xe; - $y0 = $diff+$this->rect->y; - $x0 = $xe; - $x1 = $this->rect->x; - while( $y1 <= $ye ) { - $aImg->Line($x0,$y0,$x1,$y1); - $y1 += $this->linespacing; - $y0 += $this->linespacing; - } - - $diff = $y1-$ye; - $y1 = $ye; - $x1 = $diff + $this->rect->x; - } - - while( $y0 <= $ye ) { - $aImg->Line($x0,$y0,$x1,$y1); - $y0 += $this->linespacing; - $x1 += $this->linespacing; - } - } -} - -//===================================================================== -// Class RectPatternLDiag -// Implements left diagonal pattern -//===================================================================== -class RectPatternLDiag extends RectPattern { - - function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) { - $this->linespacing = $aLineSpacing; - parent::__construct($aColor,$aWeight); - } - - function DoPattern($aImg) { - // -------------------- - // |\ \ \ \ \ | - // | \ \ \ \ \| - // | \ \ \ \ | - // |------------------| - $xe = $this->rect->xe; - $ye = $this->rect->ye; - $x0 = $this->rect->x + round($this->linespacing/2); - $y0 = $this->rect->ye; - $x1 = $this->rect->x; - $y1 = $this->rect->ye - round($this->linespacing/2); - - while($x0<=$xe && $y1>=$this->rect->y) { - $aImg->Line($x0,$y0,$x1,$y1); - $x0 += $this->linespacing; - $y1 -= $this->linespacing; - } - if( $xe-$x1 > $ye-$this->rect->y ) { - // Width larger than height - $x1 = $this->rect->x + ($this->rect->y-$y1); - $y0=$ye; $y1=$this->rect->y; - while( $x0 <= $xe ) { - $aImg->Line($x0,$y0,$x1,$y1); - $x0 += $this->linespacing; - $x1 += $this->linespacing; - } - - $y0=$this->rect->ye - ($x0-$xe); - $x0=$xe; - } - else { - // Height larger than width - $diff = $x0-$xe; - $y0 = $ye-$diff; - $x0 = $xe; - while( $y1 >= $this->rect->y ) { - $aImg->Line($x0,$y0,$x1,$y1); - $y0 -= $this->linespacing; - $y1 -= $this->linespacing; - } - $diff = $this->rect->y - $y1; - $x1 = $this->rect->x + $diff; - $y1 = $this->rect->y; - } - while( $y0 >= $this->rect->y ) { - $aImg->Line($x0,$y0,$x1,$y1); - $y0 -= $this->linespacing; - $x1 += $this->linespacing; - } - } -} - -//===================================================================== -// Class RectPattern3DPlane -// Implements "3D" plane pattern -//===================================================================== -class RectPattern3DPlane extends RectPattern { - private $alpha=50; // Parameter that specifies the distance - // to "simulated" horizon in pixel from the - // top of the band. Specifies how fast the lines - // converge. - - function __construct($aColor="black",$aWeight=1) { - parent::__construct($aColor,$aWeight); - $this->SetDensity(10); // Slightly larger default - } - - function SetHorizon($aHorizon) { - $this->alpha=$aHorizon; - } - - function DoPattern($aImg) { - // "Fake" a nice 3D grid-effect. - $x0 = $this->rect->x + $this->rect->w/2; - $y0 = $this->rect->y; - $x1 = $x0; - $y1 = $this->rect->ye; - $x0_right = $x0; - $x1_right = $x1; - - // BTW "apa" means monkey in Swedish but is really a shortform for - // "alpha+a" which was the labels I used on paper when I derived the - // geometric to get the 3D perspective right. - // $apa is the height of the bounding rectangle plus the distance to the - // artifical horizon (alpha) - $apa = $this->rect->h + $this->alpha; - - // Three cases and three loops - // 1) The endpoint of the line ends on the bottom line - // 2) The endpoint ends on the side - // 3) Horizontal lines - - // Endpoint falls on bottom line - $middle=$this->rect->x + $this->rect->w/2; - $dist=$this->linespacing; - $factor=$this->alpha /($apa); - while($x1>$this->rect->x) { - $aImg->Line($x0,$y0,$x1,$y1); - $aImg->Line($x0_right,$y0,$x1_right,$y1); - $x1 = $middle - $dist; - $x0 = $middle - $dist * $factor; - $x1_right = $middle + $dist; - $x0_right = $middle + $dist * $factor; - $dist += $this->linespacing; - } - - // Endpoint falls on sides - $dist -= $this->linespacing; - $d=$this->rect->w/2; - $c = $apa - $d*$apa/$dist; - while( $x0>$this->rect->x ) { - $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c); - $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c); - $dist += $this->linespacing; - $x0 = $middle - $dist * $factor; - $x1 = $middle - $dist; - $x0_right = $middle + $dist * $factor; - $c = $apa - $d*$apa/$dist; - } - - // Horizontal lines - // They need some serious consideration since they are a function - // of perspective depth (alpha) and density (linespacing) - $x0=$this->rect->x; - $x1=$this->rect->xe; - $y=$this->rect->ye; - - // The first line is drawn directly. Makes the loop below slightly - // more readable. - $aImg->Line($x0,$y,$x1,$y); - $hls = $this->linespacing; - - // A correction factor for vertical "brick" line spacing to account for - // a) the difference in number of pixels hor vs vert - // b) visual apperance to make the first layer of "bricks" look more - // square. - $vls = $this->linespacing*0.6; - - $ds = $hls*($apa-$vls)/$apa; - // Get the slope for the "perspective line" going from bottom right - // corner to top left corner of the "first" brick. - - // Uncomment the following lines if you want to get a visual understanding - // of what this helpline does. BTW this mimics the way you would get the - // perspective right when drawing on paper. - /* - $x0 = $middle; - $y0 = $this->rect->ye; - $len=floor(($this->rect->ye-$this->rect->y)/$vls); - $x1 = $middle+round($len*$ds); - $y1 = $this->rect->ye-$len*$vls; - $aImg->PushColor("red"); - $aImg->Line($x0,$y0,$x1,$y1); - $aImg->PopColor(); - */ - - $y -= $vls; - $k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds)); - $dist = $hls; - while( $y>$this->rect->y ) { - $aImg->Line($this->rect->x,$y,$this->rect->xe,$y); - $adj = $k*$dist/(1+$dist*$k/$apa); - if( $adj < 2 ) $adj=1; - $y = $this->rect->ye - round($adj); - $dist += $hls; - } - } -} - -//===================================================================== -// Class RectPatternCross -// Vert/Hor crosses -//===================================================================== -class RectPatternCross extends RectPattern { - private $vert=null; - private $hor=null; - function __construct($aColor="black",$aWeight=1) { - parent::__construct($aColor,$aWeight); - $this->vert = new RectPatternVert($aColor,$aWeight); - $this->hor = new RectPatternHor($aColor,$aWeight); - } - - function SetOrder($aDepth) { - $this->vert->SetOrder($aDepth); - $this->hor->SetOrder($aDepth); - } - - function SetPos($aRect) { - parent::SetPos($aRect); - $this->vert->SetPos($aRect); - $this->hor->SetPos($aRect); - } - - function SetDensity($aDens) { - $this->vert->SetDensity($aDens); - $this->hor->SetDensity($aDens); - } - - function DoPattern($aImg) { - $this->vert->DoPattern($aImg); - $this->hor->DoPattern($aImg); - } -} - -//===================================================================== -// Class RectPatternDiagCross -// Vert/Hor crosses -//===================================================================== - -class RectPatternDiagCross extends RectPattern { - private $left=null; - private $right=null; - function __construct($aColor="black",$aWeight=1) { - parent::__construct($aColor,$aWeight); - $this->right = new RectPatternRDiag($aColor,$aWeight); - $this->left = new RectPatternLDiag($aColor,$aWeight); - } - - function SetOrder($aDepth) { - $this->left->SetOrder($aDepth); - $this->right->SetOrder($aDepth); - } - - function SetPos($aRect) { - parent::SetPos($aRect); - $this->left->SetPos($aRect); - $this->right->SetPos($aRect); - } - - function SetDensity($aDens) { - $this->left->SetDensity($aDens); - $this->right->SetDensity($aDens); - } - - function DoPattern($aImg) { - $this->left->DoPattern($aImg); - $this->right->DoPattern($aImg); - } - -} - -//===================================================================== -// Class RectPatternFactory -// Factory class for rectangular pattern -//===================================================================== -class RectPatternFactory { - function __construct() { - // Empty - } - function Create($aPattern,$aColor,$aWeight=1) { - switch($aPattern) { - case BAND_RDIAG: - $obj = new RectPatternRDiag($aColor,$aWeight); - break; - case BAND_LDIAG: - $obj = new RectPatternLDiag($aColor,$aWeight); - break; - case BAND_SOLID: - $obj = new RectPatternSolid($aColor,$aWeight); - break; - case BAND_VLINE: - $obj = new RectPatternVert($aColor,$aWeight); - break; - case BAND_HLINE: - $obj = new RectPatternHor($aColor,$aWeight); - break; - case BAND_3DPLANE: - $obj = new RectPattern3DPlane($aColor,$aWeight); - break; - case BAND_HVCROSS: - $obj = new RectPatternCross($aColor,$aWeight); - break; - case BAND_DIAGCROSS: - $obj = new RectPatternDiagCross($aColor,$aWeight); - break; - default: - JpGraphError::RaiseL(16003,$aPattern); - //(" Unknown pattern specification ($aPattern)"); - } - return $obj; - } -} - - -//===================================================================== -// Class PlotBand -// Factory class which is used by the client. -// It is responsible for factoring the corresponding pattern -// concrete class. -//===================================================================== -class PlotBand { - public $depth; // Determine if band should be over or under the plots - private $prect=null; - private $dir, $min, $max; - - function __construct($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) { - $f = new RectPatternFactory(); - $this->prect = $f->Create($aPattern,$aColor,$aWeight); - if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) ) - JpGraphError::RaiseL(16004); - //('Min value for plotband is larger than specified max value. Please correct.'); - $this->dir = $aDir; - $this->min = $aMin; - $this->max = $aMax; - $this->depth=$aDepth; - } - - // Set position. aRect contains absolute image coordinates - function SetPos($aRect) { - assert( $this->prect != null ) ; - $this->prect->SetPos($aRect); - } - - function ShowFrame($aFlag=true) { - $this->prect->ShowFrame($aFlag); - } - - // Set z-order. In front of pplot or in the back - function SetOrder($aDepth) { - $this->depth=$aDepth; - } - - function SetDensity($aDens) { - $this->prect->SetDensity($aDens); - } - - function GetDir() { - return $this->dir; - } - - function GetMin() { - return $this->min; - } - - function GetMax() { - return $this->max; - } - - function PreStrokeAdjust($aGraph) { - // Nothing to do - } - - // Display band - function Stroke($aImg,$aXScale,$aYScale) { - assert( $this->prect != null ) ; - if( $this->dir == HORIZONTAL ) { - if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal(); - if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal(); - - // Only draw the bar if it actually appears in the range - if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) { - - // Trucate to limit of axis - $this->min = max($this->min, $aYScale->GetMinVal()); - $this->max = min($this->max, $aYScale->GetMaxVal()); - - $x=$aXScale->scale_abs[0]; - $y=$aYScale->Translate($this->max); - $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1; - $height=abs($y-$aYScale->Translate($this->min))+1; - $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); - $this->prect->Stroke($aImg); - } - } - else { // VERTICAL - if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal(); - if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal(); - - // Only draw the bar if it actually appears in the range - if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) { - - // Trucate to limit of axis - $this->min = max($this->min, $aXScale->GetMinVal()); - $this->max = min($this->max, $aXScale->GetMaxVal()); - - $y=$aYScale->scale_abs[1]; - $x=$aXScale->Translate($this->min); - $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]); - $width=abs($x-$aXScale->Translate($this->max)); - $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); - $this->prect->Stroke($aImg); - } - } - } -} - - -?> +x=$aX; + $this->y=$aY; + $this->w=$aWidth; + $this->h=$aHeight; + $this->xe=$aX+$aWidth-1; + $this->ye=$aY+$aHeight-1; + } +} + +//===================================================================== +// Class RectPattern +// Base class for pattern hierarchi that is used to display patterned +// bands on the graph. Any subclass that doesn't override Stroke() +// must at least implement method DoPattern($aImg) which is responsible +// for drawing the pattern onto the graph. +//===================================================================== +class RectPattern { + protected $color; + protected $weight; + protected $rect=null; + protected $doframe=true; + protected $linespacing; // Line spacing in pixels + protected $iBackgroundColor=-1; // Default is no background fill + + function __construct($aColor,$aWeight=1) { + $this->color = $aColor; + $this->weight = $aWeight; + } + + function SetBackground($aBackgroundColor) { + $this->iBackgroundColor=$aBackgroundColor; + } + + function SetPos($aRect) { + $this->rect = $aRect; + } + + function ShowFrame($aShow=true) { + $this->doframe=$aShow; + } + + function SetDensity($aDens) { + if( $aDens < 1 || $aDens > 100 ) + JpGraphError::RaiseL(16001,$aDens); + //(" Desity for pattern must be between 1 and 100. (You tried $aDens)"); + // 1% corresponds to linespacing=50 + // 100 % corresponds to linespacing 1 + $this->linespacing = floor(((100-$aDens)/100.0)*50)+1; + + } + + function Stroke($aImg) { + if( $this->rect == null ) + JpGraphError::RaiseL(16002); + //(" No positions specified for pattern."); + + if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) { + $aImg->SetColor($this->iBackgroundColor); + $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); + } + + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->weight); + + // Virtual function implemented by subclass + $this->DoPattern($aImg); + + // Frame around the pattern area + if( $this->doframe ) + $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); + } + +} + + +//===================================================================== +// Class RectPatternSolid +// Implements a solid band +//===================================================================== +class RectPatternSolid extends RectPattern { + + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + } + + function DoPattern($aImg) { + $aImg->SetColor($this->color); + $aImg->FilledRectangle($this->rect->x,$this->rect->y, + $this->rect->xe,$this->rect->ye); + } +} + +//===================================================================== +// Class RectPatternHor +// Implements horizontal line pattern +//===================================================================== +class RectPatternHor extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) { + parent::__construct($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + function DoPattern($aImg) { + $x0 = $this->rect->x; + $x1 = $this->rect->xe; + $y = $this->rect->y; + while( $y < $this->rect->ye ) { + $aImg->Line($x0,$y,$x1,$y); + $y += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPatternVert +// Implements vertical line pattern +//===================================================================== +class RectPatternVert extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) { + parent::__construct($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + //-------------------- + // Private methods + // + function DoPattern($aImg) { + $x = $this->rect->x; + $y0 = $this->rect->y; + $y1 = $this->rect->ye; + while( $x < $this->rect->xe ) { + $aImg->Line($x,$y0,$x,$y1); + $x += $this->linespacing; + } + } +} + + +//===================================================================== +// Class RectPatternRDiag +// Implements right diagonal pattern +//===================================================================== +class RectPatternRDiag extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) { + parent::__construct($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + function DoPattern($aImg) { + // -------------------- + // | / / / / /| + // |/ / / / / | + // | / / / / | + // -------------------- + $xe = $this->rect->xe; + $ye = $this->rect->ye; + $x0 = $this->rect->x + round($this->linespacing/2); + $y0 = $this->rect->y; + $x1 = $this->rect->x; + $y1 = $this->rect->y + round($this->linespacing/2); + + while($x0<=$xe && $y1<=$ye) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $y1 += $this->linespacing; + } + + if( $xe-$x1 > $ye-$y0 ) { + // Width larger than height + $x1 = $this->rect->x + ($y1-$ye); + $y1 = $ye; + $y0 = $this->rect->y; + while( $x0 <= $xe ) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $x1 += $this->linespacing; + } + + $y0=$this->rect->y + ($x0-$xe); + $x0=$xe; + } + else { + // Height larger than width + $diff = $x0-$xe; + $y0 = $diff+$this->rect->y; + $x0 = $xe; + $x1 = $this->rect->x; + while( $y1 <= $ye ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y1 += $this->linespacing; + $y0 += $this->linespacing; + } + + $diff = $y1-$ye; + $y1 = $ye; + $x1 = $diff + $this->rect->x; + } + + while( $y0 <= $ye ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 += $this->linespacing; + $x1 += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPatternLDiag +// Implements left diagonal pattern +//===================================================================== +class RectPatternLDiag extends RectPattern { + + function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) { + $this->linespacing = $aLineSpacing; + parent::__construct($aColor,$aWeight); + } + + function DoPattern($aImg) { + // -------------------- + // |\ \ \ \ \ | + // | \ \ \ \ \| + // | \ \ \ \ | + // |------------------| + $xe = $this->rect->xe; + $ye = $this->rect->ye; + $x0 = $this->rect->x + round($this->linespacing/2); + $y0 = $this->rect->ye; + $x1 = $this->rect->x; + $y1 = $this->rect->ye - round($this->linespacing/2); + + while($x0<=$xe && $y1>=$this->rect->y) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $y1 -= $this->linespacing; + } + if( $xe-$x1 > $ye-$this->rect->y ) { + // Width larger than height + $x1 = $this->rect->x + ($this->rect->y-$y1); + $y0=$ye; $y1=$this->rect->y; + while( $x0 <= $xe ) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $x1 += $this->linespacing; + } + + $y0=$this->rect->ye - ($x0-$xe); + $x0=$xe; + } + else { + // Height larger than width + $diff = $x0-$xe; + $y0 = $ye-$diff; + $x0 = $xe; + while( $y1 >= $this->rect->y ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 -= $this->linespacing; + $y1 -= $this->linespacing; + } + $diff = $this->rect->y - $y1; + $x1 = $this->rect->x + $diff; + $y1 = $this->rect->y; + } + while( $y0 >= $this->rect->y ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 -= $this->linespacing; + $x1 += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPattern3DPlane +// Implements "3D" plane pattern +//===================================================================== +class RectPattern3DPlane extends RectPattern { + private $alpha=50; // Parameter that specifies the distance + // to "simulated" horizon in pixel from the + // top of the band. Specifies how fast the lines + // converge. + + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + $this->SetDensity(10); // Slightly larger default + } + + function SetHorizon($aHorizon) { + $this->alpha=$aHorizon; + } + + function DoPattern($aImg) { + // "Fake" a nice 3D grid-effect. + $x0 = $this->rect->x + $this->rect->w/2; + $y0 = $this->rect->y; + $x1 = $x0; + $y1 = $this->rect->ye; + $x0_right = $x0; + $x1_right = $x1; + + // BTW "apa" means monkey in Swedish but is really a shortform for + // "alpha+a" which was the labels I used on paper when I derived the + // geometric to get the 3D perspective right. + // $apa is the height of the bounding rectangle plus the distance to the + // artifical horizon (alpha) + $apa = $this->rect->h + $this->alpha; + + // Three cases and three loops + // 1) The endpoint of the line ends on the bottom line + // 2) The endpoint ends on the side + // 3) Horizontal lines + + // Endpoint falls on bottom line + $middle=$this->rect->x + $this->rect->w/2; + $dist=$this->linespacing; + $factor=$this->alpha /($apa); + while($x1>$this->rect->x) { + $aImg->Line($x0,$y0,$x1,$y1); + $aImg->Line($x0_right,$y0,$x1_right,$y1); + $x1 = $middle - $dist; + $x0 = $middle - $dist * $factor; + $x1_right = $middle + $dist; + $x0_right = $middle + $dist * $factor; + $dist += $this->linespacing; + } + + // Endpoint falls on sides + $dist -= $this->linespacing; + $d=$this->rect->w/2; + $c = $apa - $d*$apa/$dist; + while( $x0>$this->rect->x ) { + $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c); + $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c); + $dist += $this->linespacing; + $x0 = $middle - $dist * $factor; + $x1 = $middle - $dist; + $x0_right = $middle + $dist * $factor; + $c = $apa - $d*$apa/$dist; + } + + // Horizontal lines + // They need some serious consideration since they are a function + // of perspective depth (alpha) and density (linespacing) + $x0=$this->rect->x; + $x1=$this->rect->xe; + $y=$this->rect->ye; + + // The first line is drawn directly. Makes the loop below slightly + // more readable. + $aImg->Line($x0,$y,$x1,$y); + $hls = $this->linespacing; + + // A correction factor for vertical "brick" line spacing to account for + // a) the difference in number of pixels hor vs vert + // b) visual apperance to make the first layer of "bricks" look more + // square. + $vls = $this->linespacing*0.6; + + $ds = $hls*($apa-$vls)/$apa; + // Get the slope for the "perspective line" going from bottom right + // corner to top left corner of the "first" brick. + + // Uncomment the following lines if you want to get a visual understanding + // of what this helpline does. BTW this mimics the way you would get the + // perspective right when drawing on paper. + /* + $x0 = $middle; + $y0 = $this->rect->ye; + $len=floor(($this->rect->ye-$this->rect->y)/$vls); + $x1 = $middle+round($len*$ds); + $y1 = $this->rect->ye-$len*$vls; + $aImg->PushColor("red"); + $aImg->Line($x0,$y0,$x1,$y1); + $aImg->PopColor(); + */ + + $y -= $vls; + $k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds)); + $dist = $hls; + while( $y>$this->rect->y ) { + $aImg->Line($this->rect->x,$y,$this->rect->xe,$y); + $adj = $k*$dist/(1+$dist*$k/$apa); + if( $adj < 2 ) $adj=1; + $y = $this->rect->ye - round($adj); + $dist += $hls; + } + } +} + +//===================================================================== +// Class RectPatternCross +// Vert/Hor crosses +//===================================================================== +class RectPatternCross extends RectPattern { + private $vert=null; + private $hor=null; + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + $this->vert = new RectPatternVert($aColor,$aWeight); + $this->hor = new RectPatternHor($aColor,$aWeight); + } + + function SetOrder($aDepth) { + $this->vert->SetOrder($aDepth); + $this->hor->SetOrder($aDepth); + } + + function SetPos($aRect) { + parent::SetPos($aRect); + $this->vert->SetPos($aRect); + $this->hor->SetPos($aRect); + } + + function SetDensity($aDens) { + $this->vert->SetDensity($aDens); + $this->hor->SetDensity($aDens); + } + + function DoPattern($aImg) { + $this->vert->DoPattern($aImg); + $this->hor->DoPattern($aImg); + } +} + +//===================================================================== +// Class RectPatternDiagCross +// Vert/Hor crosses +//===================================================================== + +class RectPatternDiagCross extends RectPattern { + private $left=null; + private $right=null; + function __construct($aColor="black",$aWeight=1) { + parent::__construct($aColor,$aWeight); + $this->right = new RectPatternRDiag($aColor,$aWeight); + $this->left = new RectPatternLDiag($aColor,$aWeight); + } + + function SetOrder($aDepth) { + $this->left->SetOrder($aDepth); + $this->right->SetOrder($aDepth); + } + + function SetPos($aRect) { + parent::SetPos($aRect); + $this->left->SetPos($aRect); + $this->right->SetPos($aRect); + } + + function SetDensity($aDens) { + $this->left->SetDensity($aDens); + $this->right->SetDensity($aDens); + } + + function DoPattern($aImg) { + $this->left->DoPattern($aImg); + $this->right->DoPattern($aImg); + } + +} + +//===================================================================== +// Class RectPatternFactory +// Factory class for rectangular pattern +//===================================================================== +class RectPatternFactory { + function __construct() { + // Empty + } + function Create($aPattern,$aColor,$aWeight=1) { + switch($aPattern) { + case BAND_RDIAG: + $obj = new RectPatternRDiag($aColor,$aWeight); + break; + case BAND_LDIAG: + $obj = new RectPatternLDiag($aColor,$aWeight); + break; + case BAND_SOLID: + $obj = new RectPatternSolid($aColor,$aWeight); + break; + case BAND_VLINE: + $obj = new RectPatternVert($aColor,$aWeight); + break; + case BAND_HLINE: + $obj = new RectPatternHor($aColor,$aWeight); + break; + case BAND_3DPLANE: + $obj = new RectPattern3DPlane($aColor,$aWeight); + break; + case BAND_HVCROSS: + $obj = new RectPatternCross($aColor,$aWeight); + break; + case BAND_DIAGCROSS: + $obj = new RectPatternDiagCross($aColor,$aWeight); + break; + default: + JpGraphError::RaiseL(16003,$aPattern); + //(" Unknown pattern specification ($aPattern)"); + } + return $obj; + } +} + + +//===================================================================== +// Class PlotBand +// Factory class which is used by the client. +// It is responsible for factoring the corresponding pattern +// concrete class. +//===================================================================== +class PlotBand { + public $depth; // Determine if band should be over or under the plots + private $prect=null; + private $dir, $min, $max; + + function __construct($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) { + $f = new RectPatternFactory(); + $this->prect = $f->Create($aPattern,$aColor,$aWeight); + if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) ) + JpGraphError::RaiseL(16004); + //('Min value for plotband is larger than specified max value. Please correct.'); + $this->dir = $aDir; + $this->min = $aMin; + $this->max = $aMax; + $this->depth=$aDepth; + } + + // Set position. aRect contains absolute image coordinates + function SetPos($aRect) { + assert( $this->prect != null ) ; + $this->prect->SetPos($aRect); + } + + function ShowFrame($aFlag=true) { + $this->prect->ShowFrame($aFlag); + } + + // Set z-order. In front of pplot or in the back + function SetOrder($aDepth) { + $this->depth=$aDepth; + } + + function SetDensity($aDens) { + $this->prect->SetDensity($aDens); + } + + function GetDir() { + return $this->dir; + } + + function GetMin() { + return $this->min; + } + + function GetMax() { + return $this->max; + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do + } + + // Display band + function Stroke($aImg,$aXScale,$aYScale) { + assert( $this->prect != null ) ; + if( $this->dir == HORIZONTAL ) { + if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal(); + if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal(); + + // Only draw the bar if it actually appears in the range + if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) { + + // Trucate to limit of axis + $this->min = max($this->min, $aYScale->GetMinVal()); + $this->max = min($this->max, $aYScale->GetMaxVal()); + + $x=$aXScale->scale_abs[0]; + $y=$aYScale->Translate($this->max); + $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1; + $height=abs($y-$aYScale->Translate($this->min))+1; + $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); + $this->prect->Stroke($aImg); + } + } + else { // VERTICAL + if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal(); + if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal(); + + // Only draw the bar if it actually appears in the range + if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) { + + // Trucate to limit of axis + $this->min = max($this->min, $aXScale->GetMinVal()); + $this->max = min($this->max, $aXScale->GetMaxVal()); + + $y=$aYScale->scale_abs[1]; + $x=$aXScale->Translate($this->min); + $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]); + $width=abs($x-$aXScale->Translate($this->max)); + $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); + $this->prect->Stroke($aImg); + } + } + } +} + + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_plotline.php b/ext/jpgraph-3.0.7/src/jpgraph_plotline.php index 7c19219..2ca7ed0 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_plotline.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_plotline.php @@ -1,138 +1,138 @@ -direction = $aDir; - $this->color=$aColor; - $this->weight=$aWeight; - $this->scaleposition=$aPos; - } - - function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { - $this->legend = $aLegend; - $this->legendcsimtarget = $aCSIM; - $this->legendcsimwintarget = $aCSIMWinTarget; - $this->legendcsimalt = $aCSIMAlt; - } - - function HideLegend($f=true) { - $this->hidelegend = $f; - } - - function SetPosition($aScalePosition) { - $this->scaleposition=$aScalePosition; - } - - function SetDirection($aDir) { - $this->direction = $aDir; - } - - function SetColor($aColor) { - $this->color=$aColor; - } - - function SetWeight($aWeight) { - $this->weight=$aWeight; - } - - function SetLineStyle($aStyle) { - $this->iLineStyle = $aStyle; - } - - //--------------- - // PRIVATE METHODS - - function DoLegend($graph) { - if( !$this->hidelegend ) $this->Legend($graph); - } - - // Framework function the chance for each plot class to set a legend - function Legend($aGraph) { - if( $this->legend != '' ) { - $dummyPlotMark = new PlotMark(); - $lineStyle = 1; - $aGraph->legend->Add($this->legend,$this->color,$dummyPlotMark,$lineStyle, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - } - - function PreStrokeAdjust($aGraph) { - // Nothing to do - } - - // Called by framework to allow the object to draw - // optional information in the margin area - function StrokeMargin($aImg) { - // Nothing to do - } - - // Framework function to allow the object to adjust the scale - function PrescaleSetup($aGraph) { - // Nothing to do - } - - function Min() { - return array(null,null); - } - - function Max() { - return array(null,null); - } - - function _Stroke($aImg,$aMinX,$aMinY,$aMaxX,$aMaxY,$aXPos,$aYPos) { - $aImg->SetColor($this->color); - $aImg->SetLineWeight($this->weight); - $oldStyle = $aImg->SetLineStyle($this->iLineStyle); - if( $this->direction == VERTICAL ) { - $ymin_abs = $aMinY; - $ymax_abs = $aMaxY; - $xpos_abs = $aXPos; - $aImg->StyleLine($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); - } - elseif( $this->direction == HORIZONTAL ) { - $xmin_abs = $aMinX; - $xmax_abs = $aMaxX; - $ypos_abs = $aYPos; - $aImg->StyleLine($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); - } - else { - JpGraphError::RaiseL(25125);//(" Illegal direction for static line"); - } - $aImg->SetLineStyle($oldStyle); - } - - function Stroke($aImg,$aXScale,$aYScale) { - $this->_Stroke($aImg, - $aImg->left_margin, - $aYScale->Translate($aYScale->GetMinVal()), - $aImg->width-$aImg->right_margin, - $aYScale->Translate($aYScale->GetMaxVal()), - $aXScale->Translate($this->scaleposition), - $aYScale->Translate($this->scaleposition) - ); - } -} - - +direction = $aDir; + $this->color=$aColor; + $this->weight=$aWeight; + $this->scaleposition=$aPos; + } + + function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimwintarget = $aCSIMWinTarget; + $this->legendcsimalt = $aCSIMAlt; + } + + function HideLegend($f=true) { + $this->hidelegend = $f; + } + + function SetPosition($aScalePosition) { + $this->scaleposition=$aScalePosition; + } + + function SetDirection($aDir) { + $this->direction = $aDir; + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + function SetLineStyle($aStyle) { + $this->iLineStyle = $aStyle; + } + + //--------------- + // PRIVATE METHODS + + function DoLegend($graph) { + if( !$this->hidelegend ) $this->Legend($graph); + } + + // Framework function the chance for each plot class to set a legend + function Legend($aGraph) { + if( $this->legend != '' ) { + $dummyPlotMark = new PlotMark(); + $lineStyle = 1; + $aGraph->legend->Add($this->legend,$this->color,$dummyPlotMark,$lineStyle, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do + } + + // Called by framework to allow the object to draw + // optional information in the margin area + function StrokeMargin($aImg) { + // Nothing to do + } + + // Framework function to allow the object to adjust the scale + function PrescaleSetup($aGraph) { + // Nothing to do + } + + function Min() { + return array(null,null); + } + + function Max() { + return array(null,null); + } + + function _Stroke($aImg,$aMinX,$aMinY,$aMaxX,$aMaxY,$aXPos,$aYPos) { + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->weight); + $oldStyle = $aImg->SetLineStyle($this->iLineStyle); + if( $this->direction == VERTICAL ) { + $ymin_abs = $aMinY; + $ymax_abs = $aMaxY; + $xpos_abs = $aXPos; + $aImg->StyleLine($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); + } + elseif( $this->direction == HORIZONTAL ) { + $xmin_abs = $aMinX; + $xmax_abs = $aMaxX; + $ypos_abs = $aYPos; + $aImg->StyleLine($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); + } + else { + JpGraphError::RaiseL(25125);//(" Illegal direction for static line"); + } + $aImg->SetLineStyle($oldStyle); + } + + function Stroke($aImg,$aXScale,$aYScale) { + $this->_Stroke($aImg, + $aImg->left_margin, + $aYScale->Translate($aYScale->GetMinVal()), + $aImg->width-$aImg->right_margin, + $aYScale->Translate($aYScale->GetMaxVal()), + $aXScale->Translate($this->scaleposition), + $aYScale->Translate($this->scaleposition) + ); + } +} + + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_plotmark.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_plotmark.inc.php index 547d4ef..cea25bc 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_plotmark.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_plotmark.inc.php @@ -1,504 +1,504 @@ -title = new Text(); - $this->title->Hide(); - $this->csimareas = ''; - $this->type=-1; - } - //--------------- - // PUBLIC METHODS - function SetType($aType,$aFileName='',$aScale=1.0) { - $this->type = $aType; - if( $aType == MARK_IMG && $aFileName=='' ) { - JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.'); - } - $this->iFileName = $aFileName; - $this->iScale = $aScale; - } - - function SetCallback($aFunc) { - $this->iFormatCallback = $aFunc; - } - - function SetCallbackYX($aFunc) { - $this->iFormatCallback2 = $aFunc; - } - - function GetType() { - return $this->type; - } - - function SetColor($aColor) { - $this->color=$aColor; - } - - function SetFillColor($aFillColor) { - $this->fill_color = $aFillColor; - } - - function SetWeight($aWeight) { - $this->weight = $aWeight; - } - - // Synonym for SetWidth() - function SetSize($aWidth) { - $this->width=$aWidth; - } - - function SetWidth($aWidth) { - $this->width=$aWidth; - } - - function SetDefaultWidth() { - switch( $this->type ) { - case MARK_CIRCLE: - case MARK_FILLEDCIRCLE: - $this->width=4; - break; - default: - $this->width=7; - } - } - - function GetWidth() { - return $this->width; - } - - function Hide($aHide=true) { - $this->show = !$aHide; - } - - function Show($aShow=true) { - $this->show = $aShow; - } - - function SetCSIMAltVal($aY,$aX='') { - $this->yvalue=$aY; - $this->xvalue=$aX; - } - - function SetCSIMTarget($aTarget,$aWinTarget='') { - $this->csimtarget=$aTarget; - $this->csimwintarget=$aWinTarget; - } - - function SetCSIMAlt($aAlt) { - $this->csimalt=$aAlt; - } - - function GetCSIMAreas(){ - return $this->csimareas; - } - - function AddCSIMPoly($aPts) { - $coords = round($aPts[0]).", ".round($aPts[1]); - $n = count($aPts)/2; - for( $i=1; $i < $n; ++$i){ - $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]); - } - $this->csimareas=""; - if( !empty($this->csimtarget) ) { - $this->csimareas .= "csimtarget)."\""; - - if( !empty($this->csimwintarget) ) { - $this->csimareas .= " target=\"".$this->csimwintarget."\" "; - } - - if( !empty($this->csimalt) ) { - $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\""; - } - $this->csimareas .= " />\n"; - } - } - - function AddCSIMCircle($x,$y,$r) { - $x = round($x); $y=round($y); $r=round($r); - $this->csimareas=""; - if( !empty($this->csimtarget) ) { - $this->csimareas .= "csimtarget)."\""; - - if( !empty($this->csimwintarget) ) { - $this->csimareas .= " target=\"".$this->csimwintarget."\" "; - } - - if( !empty($this->csimalt) ) { - $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - } - - function Stroke($img,$x,$y) { - if( !$this->show ) return; - - if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) { - - if( $this->iFormatCallback != '' ) { - $f = $this->iFormatCallback; - list($width,$color,$fcolor) = call_user_func($f,$this->yvalue); - $filename = $this->iFileName; - $imgscale = $this->iScale; - } - else { - $f = $this->iFormatCallback2; - list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue); - if( $filename=="" ) $filename = $this->iFileName; - if( $imgscale=="" ) $imgscale = $this->iScale; - } - - if( $width=="" ) $width = $this->width; - if( $color=="" ) $color = $this->color; - if( $fcolor=="" ) $fcolor = $this->fill_color; - - } - else { - $fcolor = $this->fill_color; - $color = $this->color; - $width = $this->width; - $filename = $this->iFileName; - $imgscale = $this->iScale; - } - - if( $this->type == MARK_IMG || - ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) || - $this->type >= MARK_IMG_PUSHPIN ) { - - // Note: For the builtin images we use the "filename" parameter - // to denote the color - $anchor_x = 0.5; - $anchor_y = 0.5; - switch( $this->type ) { - case MARK_FLAG1: - case MARK_FLAG2: - case MARK_FLAG3: - case MARK_FLAG4: - $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename); - break; - - case MARK_IMG : - // Load an image and use that as a marker - // Small optimization, if we have already read an image don't - // waste time reading it again. - if( $this->markimg == '' || !($this->oldfilename === $filename) ) { - $this->markimg = Graph::LoadBkgImage('',$filename); - $this->oldfilename = $filename ; - } - break; - - case MARK_IMG_PUSHPIN: - case MARK_IMG_SPUSHPIN: - case MARK_IMG_LPUSHPIN: - if( $this->imgdata_pushpins == null ) { - require_once 'imgdata_pushpins.inc.php'; - $this->imgdata_pushpins = new ImgData_PushPins(); - } - $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename); - list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor(); - break; - - case MARK_IMG_SQUARE: - if( $this->imgdata_squares == null ) { - require_once 'imgdata_squares.inc.php'; - $this->imgdata_squares = new ImgData_Squares(); - } - $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename); - list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor(); - break; - - case MARK_IMG_STAR: - if( $this->imgdata_stars == null ) { - require_once 'imgdata_stars.inc.php'; - $this->imgdata_stars = new ImgData_Stars(); - } - $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename); - list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor(); - break; - - case MARK_IMG_BEVEL: - if( $this->imgdata_bevels == null ) { - require_once 'imgdata_bevels.inc.php'; - $this->imgdata_bevels = new ImgData_Bevels(); - } - $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename); - list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor(); - break; - - case MARK_IMG_DIAMOND: - if( $this->imgdata_diamonds == null ) { - require_once 'imgdata_diamonds.inc.php'; - $this->imgdata_diamonds = new ImgData_Diamonds(); - } - $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename); - list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor(); - break; - - case MARK_IMG_BALL: - case MARK_IMG_SBALL: - case MARK_IMG_MBALL: - case MARK_IMG_LBALL: - if( $this->imgdata_balls == null ) { - require_once 'imgdata_balls.inc.php'; - $this->imgdata_balls = new ImgData_Balls(); - } - $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename); - list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor(); - break; - } - - $w = $img->GetWidth($this->markimg); - $h = $img->GetHeight($this->markimg); - - $dw = round($imgscale * $w ); - $dh = round($imgscale * $h ); - - // Do potential rotation - list($x,$y) = $img->Rotate($x,$y); - - $dx = round($x-$dw*$anchor_x); - $dy = round($y-$dh*$anchor_y); - - $this->width = max($dx,$dy); - - $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h); - if( !empty($this->csimtarget) ) { - $this->csimareas = "csimtarget)."\""; - - if( !empty($this->csimwintarget) ) { - $this->csimareas .= " target=\"".$this->csimwintarget."\" "; - } - - if( !empty($this->csimalt) ) { - $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); - $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; - } - $this->csimareas .= " />\n"; - } - - // Stroke title - $this->title->Align("center","top"); - $this->title->Stroke($img,$x,$y+round($dh/2)); - return; - } - - $weight = $this->weight; - $dx=round($width/2,0); - $dy=round($width/2,0); - $pts=0; - - switch( $this->type ) { - case MARK_SQUARE: - $c[]=$x-$dx;$c[]=$y-$dy; - $c[]=$x+$dx;$c[]=$y-$dy; - $c[]=$x+$dx;$c[]=$y+$dy; - $c[]=$x-$dx;$c[]=$y+$dy; - $c[]=$x-$dx;$c[]=$y-$dy; - $pts=5; - break; - case MARK_UTRIANGLE: - ++$dx;++$dy; - $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx - $c[]=$x;$c[]=$y-0.87*$dy; - $c[]=$x+$dx;$c[]=$y+0.87*$dy; - $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx - $pts=4; - break; - case MARK_DTRIANGLE: - ++$dx;++$dy; - $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx - $c[]=$x-$dx;$c[]=$y-0.87*$dy; - $c[]=$x+$dx;$c[]=$y-0.87*$dy; - $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx - $pts=4; - break; - case MARK_DIAMOND: - $c[]=$x;$c[]=$y+$dy; - $c[]=$x-$dx;$c[]=$y; - $c[]=$x;$c[]=$y-$dy; - $c[]=$x+$dx;$c[]=$y; - $c[]=$x;$c[]=$y+$dy; - $pts=5; - break; - case MARK_LEFTTRIANGLE: - $c[]=$x;$c[]=$y; - $c[]=$x;$c[]=$y+2*$dy; - $c[]=$x+$dx*2;$c[]=$y; - $c[]=$x;$c[]=$y; - $pts=4; - break; - case MARK_RIGHTTRIANGLE: - $c[]=$x-$dx*2;$c[]=$y; - $c[]=$x;$c[]=$y+2*$dy; - $c[]=$x;$c[]=$y; - $c[]=$x-$dx*2;$c[]=$y; - $pts=4; - break; - case MARK_FLASH: - $dy *= 2; - $c[]=$x+$dx/2; $c[]=$y-$dy; - $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy; - $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy; - $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy; - $img->SetLineWeight($weight); - $img->SetColor($color); - $img->Polygon($c); - $img->SetLineWeight(1); - $this->AddCSIMPoly($c); - break; - } - - if( $pts>0 ) { - $this->AddCSIMPoly($c); - $img->SetLineWeight($weight); - $img->SetColor($fcolor); - $img->FilledPolygon($c); - $img->SetColor($color); - $img->Polygon($c); - $img->SetLineWeight(1); - } - elseif( $this->type==MARK_CIRCLE ) { - $img->SetColor($color); - $img->Circle($x,$y,$width); - $this->AddCSIMCircle($x,$y,$width); - } - elseif( $this->type==MARK_FILLEDCIRCLE ) { - $img->SetColor($fcolor); - $img->FilledCircle($x,$y,$width); - $img->SetColor($color); - $img->Circle($x,$y,$width); - $this->AddCSIMCircle($x,$y,$width); - } - elseif( $this->type==MARK_CROSS ) { - // Oversize by a pixel to match the X - $img->SetColor($color); - $img->SetLineWeight($weight); - $img->Line($x,$y+$dy+1,$x,$y-$dy-1); - $img->Line($x-$dx-1,$y,$x+$dx+1,$y); - $this->AddCSIMCircle($x,$y,$dx); - } - elseif( $this->type==MARK_X ) { - $img->SetColor($color); - $img->SetLineWeight($weight); - $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); - $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); - $this->AddCSIMCircle($x,$y,$dx+$dy); - } - elseif( $this->type==MARK_STAR ) { - $img->SetColor($color); - $img->SetLineWeight($weight); - $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); - $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); - // Oversize by a pixel to match the X - $img->Line($x,$y+$dy+1,$x,$y-$dy-1); - $img->Line($x-$dx-1,$y,$x+$dx+1,$y); - $this->AddCSIMCircle($x,$y,$dx+$dy); - } - - // Stroke title - $this->title->Align("center","center"); - $this->title->Stroke($img,$x,$y); - } -} // Class - - - -//======================================================================== -// CLASS ImgData -// Description: Base class for all image data classes that contains the -// real image data. -//======================================================================== -class ImgData { - protected $name = ''; // Each subclass gives a name - protected $an = array(); // Data array names - protected $colors = array(); // Available colors - protected $index = array(); // Index for colors - protected $maxidx = 0 ; // Max color index - protected $anchor_x=0.5, $anchor_y=0.5 ; // Where is the center of the image - - function __construct() { - // Empty - } - - // Create a GD image from the data and return a GD handle - function GetImg($aMark,$aIdx) { - $n = $this->an[$aMark]; - if( is_string($aIdx) ) { - if( !in_array($aIdx,$this->colors) ) { - JpGraphError::RaiseL(23001,$this->name,$aIdx);//('This marker "'.($this->name).'" does not exist in color: '.$aIdx); - } - $idx = $this->index[$aIdx]; - } - elseif( !is_integer($aIdx) || - (is_integer($aIdx) && $aIdx > $this->maxidx ) ) { - JpGraphError::RaiseL(23002,$this->name);//('Mark color index too large for marker "'.($this->name).'"'); - } - else - $idx = $aIdx ; - return Image::CreateFromString(base64_decode($this->{$n}[$idx][1])); - } - - function GetAnchor() { - return array($this->anchor_x,$this->anchor_y); - } -} - - -// Keep a global flag cache to reduce memory usage -$_gFlagCache=array( -1 => null, -2 => null, -3 => null, -4 => null, -); -// Only supposed to b called as statics -class FlagCache { - - static function GetFlagImgByName($aSize,$aName) { - global $_gFlagCache; - require_once('jpgraph_flags.php'); - if( $_gFlagCache[$aSize] === null ) { - $_gFlagCache[$aSize] = new FlagImages($aSize); - } - $f = $_gFlagCache[$aSize]; - $idx = $f->GetIdxByName($aName,$aFullName); - return $f->GetImgByIdx($idx); - } -} - +title = new Text(); + $this->title->Hide(); + $this->csimareas = ''; + $this->type=-1; + } + //--------------- + // PUBLIC METHODS + function SetType($aType,$aFileName='',$aScale=1.0) { + $this->type = $aType; + if( $aType == MARK_IMG && $aFileName=='' ) { + JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.'); + } + $this->iFileName = $aFileName; + $this->iScale = $aScale; + } + + function SetCallback($aFunc) { + $this->iFormatCallback = $aFunc; + } + + function SetCallbackYX($aFunc) { + $this->iFormatCallback2 = $aFunc; + } + + function GetType() { + return $this->type; + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetFillColor($aFillColor) { + $this->fill_color = $aFillColor; + } + + function SetWeight($aWeight) { + $this->weight = $aWeight; + } + + // Synonym for SetWidth() + function SetSize($aWidth) { + $this->width=$aWidth; + } + + function SetWidth($aWidth) { + $this->width=$aWidth; + } + + function SetDefaultWidth() { + switch( $this->type ) { + case MARK_CIRCLE: + case MARK_FILLEDCIRCLE: + $this->width=4; + break; + default: + $this->width=7; + } + } + + function GetWidth() { + return $this->width; + } + + function Hide($aHide=true) { + $this->show = !$aHide; + } + + function Show($aShow=true) { + $this->show = $aShow; + } + + function SetCSIMAltVal($aY,$aX='') { + $this->yvalue=$aY; + $this->xvalue=$aX; + } + + function SetCSIMTarget($aTarget,$aWinTarget='') { + $this->csimtarget=$aTarget; + $this->csimwintarget=$aWinTarget; + } + + function SetCSIMAlt($aAlt) { + $this->csimalt=$aAlt; + } + + function GetCSIMAreas(){ + return $this->csimareas; + } + + function AddCSIMPoly($aPts) { + $coords = round($aPts[0]).", ".round($aPts[1]); + $n = count($aPts)/2; + for( $i=1; $i < $n; ++$i){ + $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]); + } + $this->csimareas=""; + if( !empty($this->csimtarget) ) { + $this->csimareas .= "csimtarget)."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimareas .= " target=\"".$this->csimwintarget."\" "; + } + + if( !empty($this->csimalt) ) { + $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\""; + } + $this->csimareas .= " />\n"; + } + } + + function AddCSIMCircle($x,$y,$r) { + $x = round($x); $y=round($y); $r=round($r); + $this->csimareas=""; + if( !empty($this->csimtarget) ) { + $this->csimareas .= "csimtarget)."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimareas .= " target=\"".$this->csimwintarget."\" "; + } + + if( !empty($this->csimalt) ) { + $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + function Stroke($img,$x,$y) { + if( !$this->show ) return; + + if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) { + + if( $this->iFormatCallback != '' ) { + $f = $this->iFormatCallback; + list($width,$color,$fcolor) = call_user_func($f,$this->yvalue); + $filename = $this->iFileName; + $imgscale = $this->iScale; + } + else { + $f = $this->iFormatCallback2; + list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue); + if( $filename=="" ) $filename = $this->iFileName; + if( $imgscale=="" ) $imgscale = $this->iScale; + } + + if( $width=="" ) $width = $this->width; + if( $color=="" ) $color = $this->color; + if( $fcolor=="" ) $fcolor = $this->fill_color; + + } + else { + $fcolor = $this->fill_color; + $color = $this->color; + $width = $this->width; + $filename = $this->iFileName; + $imgscale = $this->iScale; + } + + if( $this->type == MARK_IMG || + ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) || + $this->type >= MARK_IMG_PUSHPIN ) { + + // Note: For the builtin images we use the "filename" parameter + // to denote the color + $anchor_x = 0.5; + $anchor_y = 0.5; + switch( $this->type ) { + case MARK_FLAG1: + case MARK_FLAG2: + case MARK_FLAG3: + case MARK_FLAG4: + $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename); + break; + + case MARK_IMG : + // Load an image and use that as a marker + // Small optimization, if we have already read an image don't + // waste time reading it again. + if( $this->markimg == '' || !($this->oldfilename === $filename) ) { + $this->markimg = Graph::LoadBkgImage('',$filename); + $this->oldfilename = $filename ; + } + break; + + case MARK_IMG_PUSHPIN: + case MARK_IMG_SPUSHPIN: + case MARK_IMG_LPUSHPIN: + if( $this->imgdata_pushpins == null ) { + require_once 'imgdata_pushpins.inc.php'; + $this->imgdata_pushpins = new ImgData_PushPins(); + } + $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor(); + break; + + case MARK_IMG_SQUARE: + if( $this->imgdata_squares == null ) { + require_once 'imgdata_squares.inc.php'; + $this->imgdata_squares = new ImgData_Squares(); + } + $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor(); + break; + + case MARK_IMG_STAR: + if( $this->imgdata_stars == null ) { + require_once 'imgdata_stars.inc.php'; + $this->imgdata_stars = new ImgData_Stars(); + } + $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor(); + break; + + case MARK_IMG_BEVEL: + if( $this->imgdata_bevels == null ) { + require_once 'imgdata_bevels.inc.php'; + $this->imgdata_bevels = new ImgData_Bevels(); + } + $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor(); + break; + + case MARK_IMG_DIAMOND: + if( $this->imgdata_diamonds == null ) { + require_once 'imgdata_diamonds.inc.php'; + $this->imgdata_diamonds = new ImgData_Diamonds(); + } + $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor(); + break; + + case MARK_IMG_BALL: + case MARK_IMG_SBALL: + case MARK_IMG_MBALL: + case MARK_IMG_LBALL: + if( $this->imgdata_balls == null ) { + require_once 'imgdata_balls.inc.php'; + $this->imgdata_balls = new ImgData_Balls(); + } + $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor(); + break; + } + + $w = $img->GetWidth($this->markimg); + $h = $img->GetHeight($this->markimg); + + $dw = round($imgscale * $w ); + $dh = round($imgscale * $h ); + + // Do potential rotation + list($x,$y) = $img->Rotate($x,$y); + + $dx = round($x-$dw*$anchor_x); + $dy = round($y-$dh*$anchor_y); + + $this->width = max($dx,$dy); + + $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h); + if( !empty($this->csimtarget) ) { + $this->csimareas = "csimtarget)."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimareas .= " target=\"".$this->csimwintarget."\" "; + } + + if( !empty($this->csimalt) ) { + $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + + // Stroke title + $this->title->Align("center","top"); + $this->title->Stroke($img,$x,$y+round($dh/2)); + return; + } + + $weight = $this->weight; + $dx=round($width/2,0); + $dy=round($width/2,0); + $pts=0; + + switch( $this->type ) { + case MARK_SQUARE: + $c[]=$x-$dx;$c[]=$y-$dy; + $c[]=$x+$dx;$c[]=$y-$dy; + $c[]=$x+$dx;$c[]=$y+$dy; + $c[]=$x-$dx;$c[]=$y+$dy; + $c[]=$x-$dx;$c[]=$y-$dy; + $pts=5; + break; + case MARK_UTRIANGLE: + ++$dx;++$dy; + $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $c[]=$x;$c[]=$y-0.87*$dy; + $c[]=$x+$dx;$c[]=$y+0.87*$dy; + $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $pts=4; + break; + case MARK_DTRIANGLE: + ++$dx;++$dy; + $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $c[]=$x-$dx;$c[]=$y-0.87*$dy; + $c[]=$x+$dx;$c[]=$y-0.87*$dy; + $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $pts=4; + break; + case MARK_DIAMOND: + $c[]=$x;$c[]=$y+$dy; + $c[]=$x-$dx;$c[]=$y; + $c[]=$x;$c[]=$y-$dy; + $c[]=$x+$dx;$c[]=$y; + $c[]=$x;$c[]=$y+$dy; + $pts=5; + break; + case MARK_LEFTTRIANGLE: + $c[]=$x;$c[]=$y; + $c[]=$x;$c[]=$y+2*$dy; + $c[]=$x+$dx*2;$c[]=$y; + $c[]=$x;$c[]=$y; + $pts=4; + break; + case MARK_RIGHTTRIANGLE: + $c[]=$x-$dx*2;$c[]=$y; + $c[]=$x;$c[]=$y+2*$dy; + $c[]=$x;$c[]=$y; + $c[]=$x-$dx*2;$c[]=$y; + $pts=4; + break; + case MARK_FLASH: + $dy *= 2; + $c[]=$x+$dx/2; $c[]=$y-$dy; + $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy; + $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy; + $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy; + $img->SetLineWeight($weight); + $img->SetColor($color); + $img->Polygon($c); + $img->SetLineWeight(1); + $this->AddCSIMPoly($c); + break; + } + + if( $pts>0 ) { + $this->AddCSIMPoly($c); + $img->SetLineWeight($weight); + $img->SetColor($fcolor); + $img->FilledPolygon($c); + $img->SetColor($color); + $img->Polygon($c); + $img->SetLineWeight(1); + } + elseif( $this->type==MARK_CIRCLE ) { + $img->SetColor($color); + $img->Circle($x,$y,$width); + $this->AddCSIMCircle($x,$y,$width); + } + elseif( $this->type==MARK_FILLEDCIRCLE ) { + $img->SetColor($fcolor); + $img->FilledCircle($x,$y,$width); + $img->SetColor($color); + $img->Circle($x,$y,$width); + $this->AddCSIMCircle($x,$y,$width); + } + elseif( $this->type==MARK_CROSS ) { + // Oversize by a pixel to match the X + $img->SetColor($color); + $img->SetLineWeight($weight); + $img->Line($x,$y+$dy+1,$x,$y-$dy-1); + $img->Line($x-$dx-1,$y,$x+$dx+1,$y); + $this->AddCSIMCircle($x,$y,$dx); + } + elseif( $this->type==MARK_X ) { + $img->SetColor($color); + $img->SetLineWeight($weight); + $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); + $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); + $this->AddCSIMCircle($x,$y,$dx+$dy); + } + elseif( $this->type==MARK_STAR ) { + $img->SetColor($color); + $img->SetLineWeight($weight); + $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); + $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); + // Oversize by a pixel to match the X + $img->Line($x,$y+$dy+1,$x,$y-$dy-1); + $img->Line($x-$dx-1,$y,$x+$dx+1,$y); + $this->AddCSIMCircle($x,$y,$dx+$dy); + } + + // Stroke title + $this->title->Align("center","center"); + $this->title->Stroke($img,$x,$y); + } +} // Class + + + +//======================================================================== +// CLASS ImgData +// Description: Base class for all image data classes that contains the +// real image data. +//======================================================================== +class ImgData { + protected $name = ''; // Each subclass gives a name + protected $an = array(); // Data array names + protected $colors = array(); // Available colors + protected $index = array(); // Index for colors + protected $maxidx = 0 ; // Max color index + protected $anchor_x=0.5, $anchor_y=0.5 ; // Where is the center of the image + + function __construct() { + // Empty + } + + // Create a GD image from the data and return a GD handle + function GetImg($aMark,$aIdx) { + $n = $this->an[$aMark]; + if( is_string($aIdx) ) { + if( !in_array($aIdx,$this->colors) ) { + JpGraphError::RaiseL(23001,$this->name,$aIdx);//('This marker "'.($this->name).'" does not exist in color: '.$aIdx); + } + $idx = $this->index[$aIdx]; + } + elseif( !is_integer($aIdx) || + (is_integer($aIdx) && $aIdx > $this->maxidx ) ) { + JpGraphError::RaiseL(23002,$this->name);//('Mark color index too large for marker "'.($this->name).'"'); + } + else + $idx = $aIdx ; + return Image::CreateFromString(base64_decode($this->{$n}[$idx][1])); + } + + function GetAnchor() { + return array($this->anchor_x,$this->anchor_y); + } +} + + +// Keep a global flag cache to reduce memory usage +$_gFlagCache=array( +1 => null, +2 => null, +3 => null, +4 => null, +); +// Only supposed to b called as statics +class FlagCache { + + static function GetFlagImgByName($aSize,$aName) { + global $_gFlagCache; + require_once('jpgraph_flags.php'); + if( $_gFlagCache[$aSize] === null ) { + $_gFlagCache[$aSize] = new FlagImages($aSize); + } + $f = $_gFlagCache[$aSize]; + $idx = $f->GetIdxByName($aName,$aFullName); + return $f->GetImgByIdx($idx); + } +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_polar.php b/ext/jpgraph-3.0.7/src/jpgraph_polar.php index d72ea6e..7a7a0f3 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_polar.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_polar.php @@ -1,897 +1,897 @@ -numpoints = $n/2; - $this->coord = $aData; - $this->mark = new PlotMark(); - } - - function SetWeight($aWeight) { - $this->iLineWeight = $aWeight; - } - - function SetColor($aColor){ - $this->iColor = $aColor; - } - - function SetFillColor($aColor){ - $this->iFillColor = $aColor; - } - - function Max() { - $m = $this->coord[1]; - $i=1; - while( $i < $this->numpoints ) { - $m = max($m,$this->coord[2*$i+1]); - ++$i; - } - return $m; - } - // Set href targets for CSIM - function SetCSIMTargets($aTargets,$aAlts=null) { - $this->csimtargets=$aTargets; - $this->csimalts=$aAlts; - } - - // Get all created areas - function GetCSIMareas() { - return $this->csimareas; - } - - function SetLegend($aLegend,$aCSIM="",$aCSIMAlt="") { - $this->legend = $aLegend; - $this->legendcsimtarget = $aCSIM; - $this->legendcsimalt = $aCSIMAlt; - } - - // Private methods - - function Legend($aGraph) { - $color = $this->iColor ; - if( $this->legend != "" ) { - if( $this->iFillColor!='' ) { - $color = $this->iFillColor; - $aGraph->legend->Add($this->legend,$color,$this->mark,0, - $this->legendcsimtarget,$this->legendcsimalt); - } - else { - $aGraph->legend->Add($this->legend,$color,$this->mark,$this->line_style, - $this->legendcsimtarget,$this->legendcsimalt); - } - } - } - - function Stroke($img,$scale) { - - $i=0; - $p=array(); - $this->csimareas=''; - while($i < $this->numpoints) { - list($x1,$y1) = $scale->PTranslate($this->coord[2*$i],$this->coord[2*$i+1]); - $p[2*$i] = $x1; - $p[2*$i+1] = $y1; - - if( isset($this->csimtargets[$i]) ) { - $this->mark->SetCSIMTarget($this->csimtargets[$i]); - $this->mark->SetCSIMAlt($this->csimalts[$i]); - $this->mark->SetCSIMAltVal($this->coord[2*$i], $this->coord[2*$i+1]); - $this->mark->Stroke($img,$x1,$y1); - $this->csimareas .= $this->mark->GetCSIMAreas(); - } - else { - $this->mark->Stroke($img,$x1,$y1); - } - - ++$i; - } - - if( $this->iFillColor != '' ) { - $img->SetColor($this->iFillColor); - $img->FilledPolygon($p); - } - $img->SetLineWeight($this->iLineWeight); - $img->SetColor($this->iColor); - $img->Polygon($p,$this->iFillColor!=''); - } -} - -//-------------------------------------------------------------------------- -// class PolarAxis -//-------------------------------------------------------------------------- -class PolarAxis extends Axis { - private $angle_step=15,$angle_color='lightgray',$angle_label_color='black'; - private $angle_fontfam=FF_FONT1,$angle_fontstyle=FS_NORMAL,$angle_fontsize=10; - private $angle_fontcolor = 'navy'; - private $gridminor_color='lightgray',$gridmajor_color='lightgray'; - private $show_minor_grid = false, $show_major_grid = true ; - private $show_angle_mark=true, $show_angle_grid=true, $show_angle_label=true; - private $angle_tick_len=3, $angle_tick_len2=3, $angle_tick_color='black'; - private $show_angle_tick=true; - private $radius_tick_color='black'; - - function __construct($img,$aScale) { - parent::__construct($img,$aScale); - } - - function ShowAngleDegreeMark($aFlg=true) { - $this->show_angle_mark = $aFlg; - } - - function SetAngleStep($aStep) { - $this->angle_step=$aStep; - } - - function HideTicks($aFlg=true,$aAngleFlg=true) { - parent::HideTicks($aFlg,$aFlg); - $this->show_angle_tick = !$aAngleFlg; - } - - function ShowAngleLabel($aFlg=true) { - $this->show_angle_label = $aFlg; - } - - function ShowGrid($aMajor=true,$aMinor=false,$aAngle=true) { - $this->show_minor_grid = $aMinor; - $this->show_major_grid = $aMajor; - $this->show_angle_grid = $aAngle ; - } - - function SetAngleFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=10) { - $this->angle_fontfam = $aFontFam; - $this->angle_fontstyle = $aFontStyle; - $this->angle_fontsize = $aFontSize; - } - - function SetColor($aColor,$aRadColor='',$aAngleColor='') { - if( $aAngleColor == '' ) - $aAngleColor=$aColor; - parent::SetColor($aColor,$aRadColor); - $this->angle_fontcolor = $aAngleColor; - } - - function SetGridColor($aMajorColor,$aMinorColor='',$aAngleColor='') { - if( $aMinorColor == '' ) - $aMinorColor = $aMajorColor; - if( $aAngleColor == '' ) - $aAngleColor = $aMajorColor; - - $this->gridminor_color = $aMinorColor; - $this->gridmajor_color = $aMajorColor; - $this->angle_color = $aAngleColor; - } - - function SetTickColors($aRadColor,$aAngleColor='') { - $this->radius_tick_color = $aRadColor; - $this->angle_tick_color = $aAngleColor; - } - - // Private methods - function StrokeGrid($pos) { - $x = round($this->img->left_margin + $this->img->plotwidth/2); - $this->scale->ticks->Stroke($this->img,$this->scale,$pos); - - // Stroke the minor arcs - $pmin = array(); - $p = $this->scale->ticks->ticks_pos; - $n = count($p); - $i = 0; - $this->img->SetColor($this->gridminor_color); - while( $i < $n ) { - $r = $p[$i]-$x+1; - $pmin[]=$r; - if( $this->show_minor_grid ) { - $this->img->Circle($x,$pos,$r); - } - $i++; - } - - $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; - while( $r < $limit ) { - $off = $r; - $i=1; - $r = $off + round($p[$i]-$x+1); - while( $r < $limit && $i < $n ) { - $r = $off+$p[$i]-$x; - $pmin[]=$r; - if( $this->show_minor_grid ) { - $this->img->Circle($x,$pos,$r); - } - $i++; - } - } - - // Stroke the major arcs - if( $this->show_major_grid ) { - // First determine how many minor step on - // every major step. We have recorded the minor radius - // in pmin and use these values. This is done in order - // to avoid rounding errors if we were to recalculate the - // different major radius. - $pmaj = $this->scale->ticks->maj_ticks_pos; - $p = $this->scale->ticks->ticks_pos; - if( $this->scale->name == 'lin' ) { - $step=round(($pmaj[1] - $pmaj[0])/($p[1] - $p[0])); - } - else { - $step=9; - } - $n = round(count($pmin)/$step); - $i = 0; - $this->img->SetColor($this->gridmajor_color); - $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; - $off = $r; - $i=0; - $r = $pmin[$i*$step]; - while( $r < $limit && $i < $n ) { - $r = $pmin[$i*$step]; - $this->img->Circle($x,$pos,$r); - $i++; - } - } - - // Draw angles - if( $this->show_angle_grid ) { - $this->img->SetColor($this->angle_color); - $d = max($this->img->plotheight,$this->img->plotwidth)*1.4 ; - $a = 0; - $p = $this->scale->ticks->ticks_pos; - $start_radius = $p[1]-$x; - while( $a < 360 ) { - if( $a == 90 || $a == 270 ) { - // Make sure there are no rounding problem with - // exactly vertical lines - $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, - $pos-$start_radius*sin($a/180*M_PI), - $x+$start_radius*cos($a/180*M_PI)+1, - $pos-$d*sin($a/180*M_PI)); - - } - else { - $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, - $pos-$start_radius*sin($a/180*M_PI), - $x+$d*cos($a/180*M_PI), - $pos-$d*sin($a/180*M_PI)); - } - $a += $this->angle_step; - } - } - } - - function StrokeAngleLabels($pos,$type) { - - if( !$this->show_angle_label ) - return; - - $x0 = round($this->img->left_margin+$this->img->plotwidth/2)+1; - - $d = max($this->img->plotwidth,$this->img->plotheight)*1.42; - $a = $this->angle_step; - $t = new Text(); - $t->SetColor($this->angle_fontcolor); - $t->SetFont($this->angle_fontfam,$this->angle_fontstyle,$this->angle_fontsize); - $xright = $this->img->width - $this->img->right_margin; - $ytop = $this->img->top_margin; - $xleft = $this->img->left_margin; - $ybottom = $this->img->height - $this->img->bottom_margin; - $ha = 'left'; - $va = 'center'; - $w = $this->img->plotwidth/2; - $h = $this->img->plotheight/2; - $xt = $x0; $yt = $pos; - $margin=5; - - $tl = $this->angle_tick_len ; // Outer len - $tl2 = $this->angle_tick_len2 ; // Interior len - - $this->img->SetColor($this->angle_tick_color); - $rot90 = $this->img->a == 90 ; - - if( $type == POLAR_360 ) { - - // Corner angles of the four corners - $ca1 = atan($h/$w)/M_PI*180; - $ca2 = 180-$ca1; - $ca3 = $ca1+180; - $ca4 = 360-$ca1; - $end = 360; - - while( $a < $end ) { - $ca = cos($a/180*M_PI); - $sa = sin($a/180*M_PI); - $x = $d*$ca; - $y = $d*$sa; - $xt=1000;$yt=1000; - if( $a <= $ca1 || $a >= $ca4 ) { - $yt = $pos - $w * $y/$x; - $xt = $xright + $margin; - if( $rot90 ) { - $ha = 'center'; - $va = 'top'; - } - else { - $ha = 'left'; - $va = 'center'; - } - $x1=$xright-$tl2; $x2=$xright+$tl; - $y1=$y2=$yt; - } - elseif( $a > $ca1 && $a < $ca2 ) { - $xt = $x0 + $h * $x/$y; - $yt = $ytop - $margin; - if( $rot90 ) { - $ha = 'left'; - $va = 'center'; - } - else { - $ha = 'center'; - $va = 'bottom'; - } - $y1=$ytop+$tl2;$y2=$ytop-$tl; - $x1=$x2=$xt; - } - elseif( $a >= $ca2 && $a <= $ca3 ) { - $yt = $pos + $w * $y/$x; - $xt = $xleft - $margin; - if( $rot90 ) { - $ha = 'center'; - $va = 'bottom'; - } - else { - $ha = 'right'; - $va = 'center'; - } - $x1=$xleft+$tl2;$x2=$xleft-$tl; - $y1=$y2=$yt; - } - else { - $xt = $x0 - $h * $x/$y; - $yt = $ybottom + $margin; - if( $rot90 ) { - $ha = 'right'; - $va = 'center'; - } - else { - $ha = 'center'; - $va = 'top'; - } - $y1=$ybottom-$tl2;$y2=$ybottom+$tl; - $x1=$x2=$xt; - } - if( $a != 0 && $a != 180 ) { - $t->Align($ha,$va); - if( $this->scale->clockwise ) { - $t->Set(360-$a); - } - else { - $t->Set($a); - } - if( $this->show_angle_mark && $t->font_family > 4 ) { - $a .= SymChar::Get('degree'); - } - $t->Stroke($this->img,$xt,$yt); - if( $this->show_angle_tick ) { - $this->img->Line($x1,$y1,$x2,$y2); - } - } - $a += $this->angle_step; - } - } - else { - // POLAR_HALF - $ca1 = atan($h/$w*2)/M_PI*180; - $ca2 = 180-$ca1; - $end = 180; - while( $a < $end ) { - $ca = cos($a/180*M_PI); - $sa = sin($a/180*M_PI); - $x = $d*$ca; - $y = $d*$sa; - if( $a <= $ca1 ) { - $yt = $pos - $w * $y/$x; - $xt = $xright + $margin; - if( $rot90 ) { - $ha = 'center'; - $va = 'top'; - } - else { - $ha = 'left'; - $va = 'center'; - } - $x1=$xright-$tl2; $x2=$xright+$tl; - $y1=$y2=$yt; - } - elseif( $a > $ca1 && $a < $ca2 ) { - $xt = $x0 + 2*$h * $x/$y; - $yt = $ytop - $margin; - if( $rot90 ) { - $ha = 'left'; - $va = 'center'; - } - else { - $ha = 'center'; - $va = 'bottom'; - } - $y1=$ytop+$tl2;$y2=$ytop-$tl; - $x1=$x2=$xt; - } - elseif( $a >= $ca2 ) { - $yt = $pos + $w * $y/$x; - $xt = $xleft - $margin; - if( $rot90 ) { - $ha = 'center'; - $va = 'bottom'; - } - else { - $ha = 'right'; - $va = 'center'; - } - $x1=$xleft+$tl2;$x2=$xleft-$tl; - $y1=$y2=$yt; - } - $t->Align($ha,$va); - if( $this->show_angle_mark && $t->font_family > 4 ) { - $a .= SymChar::Get('degree'); - } - $t->Set($a); - $t->Stroke($this->img,$xt,$yt); - if( $this->show_angle_tick ) { - $this->img->Line($x1,$y1,$x2,$y2); - } - $a += $this->angle_step; - } - } - } - - function Stroke($pos,$dummy=true) { - - $this->img->SetLineWeight($this->weight); - $this->img->SetColor($this->color); - $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); - if( !$this->hide_line ) { - $this->img->FilledRectangle($this->img->left_margin,$pos, - $this->img->width-$this->img->right_margin, - $pos+$this->weight-1); - } - $y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin; - if( $this->title_adjust=="high" ) { - $this->title->SetPos($this->img->width-$this->img->right_margin,$y,"right","top"); - } - elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" ) { - $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin, - $y,"center","top"); - } - elseif($this->title_adjust=="low") { - $this->title->SetPos($this->img->left_margin,$y,"left","top"); - } - else { - JpGraphError::RaiseL(17002,$this->title_adjust); - //('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); - } - - - if (!$this->hide_labels) { - $this->StrokeLabels($pos,false); - } - $this->img->SetColor($this->radius_tick_color); - $this->scale->ticks->Stroke($this->img,$this->scale,$pos); - - // - // Mirror the positions for the left side of the scale - // - $mid = 2*($this->img->left_margin+$this->img->plotwidth/2); - $n = count($this->scale->ticks->ticks_pos); - $i=0; - while( $i < $n ) { - $this->scale->ticks->ticks_pos[$i] = - $mid-$this->scale->ticks->ticks_pos[$i] ; - ++$i; - } - - $n = count($this->scale->ticks->maj_ticks_pos); - $i=0; - while( $i < $n ) { - $this->scale->ticks->maj_ticks_pos[$i] = - $mid-$this->scale->ticks->maj_ticks_pos[$i] ; - ++$i; - } - - $n = count($this->scale->ticks->maj_ticklabels_pos); - $i=1; - while( $i < $n ) { - $this->scale->ticks->maj_ticklabels_pos[$i] = - $mid-$this->scale->ticks->maj_ticklabels_pos[$i] ; - ++$i; - } - - // Draw the left side of the scale - $n = count($this->scale->ticks->ticks_pos); - $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMinTickAbsSize(); - - - // Minor ticks - if( ! $this->scale->ticks->supress_minor_tickmarks ) { - $i=1; - while( $i < $n/2 ) { - $x = round($this->scale->ticks->ticks_pos[$i]) ; - $this->img->Line($x,$pos,$x,$yu); - ++$i; - } - } - - $n = count($this->scale->ticks->maj_ticks_pos); - $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMajTickAbsSize(); - - - // Major ticks - if( ! $this->scale->ticks->supress_tickmarks ) { - $i=1; - while( $i < $n/2 ) { - $x = round($this->scale->ticks->maj_ticks_pos[$i]) ; - $this->img->Line($x,$pos,$x,$yu); - ++$i; - } - } - if (!$this->hide_labels) { - $this->StrokeLabels($pos,false); - } - $this->title->Stroke($this->img); - } -} - -class PolarScale extends LinearScale { - private $graph; - public $clockwise=false; - - function __construct($aMax,$graph,$aClockwise) { - parent::__construct(0,$aMax,'x'); - $this->graph = $graph; - $this->clockwise = $aClockwise; - } - - function SetClockwise($aFlg) { - $this->clockwise = $aFlg; - } - - function _Translate($v) { - return parent::Translate($v); - } - - function PTranslate($aAngle,$aRad) { - - $m = $this->scale[1]; - $w = $this->graph->img->plotwidth/2; - $aRad = $aRad/$m*$w; - - $a = $aAngle/180 * M_PI; - if( $this->clockwise ) { - $a = 2*M_PI-$a; - } - - $x = cos($a) * $aRad; - $y = sin($a) * $aRad; - - $x += $this->_Translate(0); - - if( $this->graph->iType == POLAR_360 ) { - $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; - } - else { - $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; - } - return array($x,$y); - } -} - -class PolarLogScale extends LogScale { - private $graph; - public $clockwise=false; - - function __construct($aMax,$graph,$aClockwise=false) { - parent::__construct(0,$aMax,'x'); - $this->graph = $graph; - $this->ticks->SetLabelLogType(LOGLABELS_MAGNITUDE); - $this->clockwise = $aClockwise; - - } - - function SetClockwise($aFlg) { - $this->clockwise = $aFlg; - } - - function PTranslate($aAngle,$aRad) { - - if( $aRad == 0 ) - $aRad = 1; - $aRad = log10($aRad); - $m = $this->scale[1]; - $w = $this->graph->img->plotwidth/2; - $aRad = $aRad/$m*$w; - - $a = $aAngle/180 * M_PI; - if( $this->clockwise ) { - $a = 2*M_PI-$a; - } - - $x = cos( $a ) * $aRad; - $y = sin( $a ) * $aRad; - - $x += $w+$this->graph->img->left_margin;//$this->_Translate(0); - if( $this->graph->iType == POLAR_360 ) { - $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; - } - else { - $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; - } - return array($x,$y); - } -} - -class PolarGraph extends Graph { - public $scale; - public $axis; - public $iType=POLAR_360; - private $iClockwise=false; - - function __construct($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { - parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline) ; - $this->SetDensity(TICKD_DENSE); - $this->SetBox(); - $this->SetMarginColor('white'); - } - - function SetDensity($aDense) { - $this->SetTickDensity(TICKD_NORMAL,$aDense); - } - - function SetClockwise($aFlg) { - $this->scale->SetClockwise($aFlg); - } - - function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { - $adj = ($this->img->height - $this->img->width)/2; - $this->SetAngle(90); - $lm2 = -$adj + ($lm-$rm+$tm+$bm)/2; - $rm2 = -$adj + (-$lm+$rm+$tm+$bm)/2; - $tm2 = $adj + ($tm-$bm+$lm+$rm)/2; - $bm2 = $adj + (-$tm+$bm+$lm+$rm)/2; - $this->SetMargin($lm2, $rm2, $tm2, $bm2); - $this->axis->SetLabelAlign('right','center'); - } - - function SetScale($aScale,$rmax=0,$dummy1=1,$dummy2=1,$dummy3=1) { - if( $aScale == 'lin' ) { - $this->scale = new PolarScale($rmax,$this,$this->iClockwise); - } - elseif( $aScale == 'log' ) { - $this->scale = new PolarLogScale($rmax,$this,$this->iClockwise); - } - else { - JpGraphError::RaiseL(17004);//('Unknown scale type for polar graph. Must be "lin" or "log"'); - } - - $this->axis = new PolarAxis($this->img,$this->scale); - $this->SetMargin(40,40,50,40); - } - - function SetType($aType) { - $this->iType = $aType; - } - - function SetPlotSize($w,$h) { - $this->SetMargin(($this->img->width-$w)/2,($this->img->width-$w)/2, - ($this->img->height-$h)/2,($this->img->height-$h)/2); - } - - // Private methods - function GetPlotsMax() { - $n = count($this->plots); - $m = $this->plots[0]->Max(); - $i=1; - while($i < $n) { - $m = max($this->plots[$i]->Max(),$m); - ++$i; - } - return $m; - } - - function Stroke($aStrokeFileName="") { - - // Start by adjusting the margin so that potential titles will fit. - $this->AdjustMarginsForTitles(); - - // If the filename is the predefined value = '_csim_special_' - // we assume that the call to stroke only needs to do enough - // to correctly generate the CSIM maps. - // We use this variable to skip things we don't strictly need - // to do to generate the image map to improve performance - // a best we can. Therefor you will see a lot of tests !$_csim in the - // code below. - $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); - - // We need to know if we have stroked the plot in the - // GetCSIMareas. Otherwise the CSIM hasn't been generated - // and in the case of GetCSIM called before stroke to generate - // CSIM without storing an image to disk GetCSIM must call Stroke. - $this->iHasStroked = true; - - //Check if we should autoscale axis - if( !$this->scale->IsSpecified() && count($this->plots)>0 ) { - $max = $this->GetPlotsMax(); - $t1 = $this->img->plotwidth; - $this->img->plotwidth /= 2; - $t2 = $this->img->left_margin; - $this->img->left_margin += $this->img->plotwidth+1; - $this->scale->AutoScale($this->img,0,$max, - $this->img->plotwidth/$this->xtick_factor/2); - $this->img->plotwidth = $t1; - $this->img->left_margin = $t2; - } - else { - // The tick calculation will use the user suplied min/max values to determine - // the ticks. If auto_ticks is false the exact user specifed min and max - // values will be used for the scale. - // If auto_ticks is true then the scale might be slightly adjusted - // so that the min and max values falls on an even major step. - //$min = 0; - $max = $this->scale->scale[1]; - $t1 = $this->img->plotwidth; - $this->img->plotwidth /= 2; - $t2 = $this->img->left_margin; - $this->img->left_margin += $this->img->plotwidth+1; - $this->scale->AutoScale($this->img,0,$max, - $this->img->plotwidth/$this->xtick_factor/2); - $this->img->plotwidth = $t1; - $this->img->left_margin = $t2; - } - - if( $this->iType == POLAR_180 ) { - $pos = $this->img->height - $this->img->bottom_margin; - } - else { - $pos = $this->img->plotheight/2 + $this->img->top_margin; - } - - if( !$_csim ) { - $this->StrokePlotArea(); - } - - $this->iDoClipping = true; - - if( $this->iDoClipping ) { - $oldimage = $this->img->CloneCanvasH(); - } - - if( !$_csim ) { - $this->axis->StrokeGrid($pos); - } - - // Stroke all plots for Y1 axis - for($i=0; $i < count($this->plots); ++$i) { - $this->plots[$i]->Stroke($this->img,$this->scale); - } - - - if( $this->iDoClipping ) { - // Clipping only supports graphs at 0 and 90 degrees - if( $this->img->a == 0 ) { - $this->img->CopyCanvasH($oldimage,$this->img->img, - $this->img->left_margin,$this->img->top_margin, - $this->img->left_margin,$this->img->top_margin, - $this->img->plotwidth+1,$this->img->plotheight+1); - } - elseif( $this->img->a == 90 ) { - $adj1 = round(($this->img->height - $this->img->width)/2); - $adj2 = round(($this->img->width - $this->img->height)/2); - $lm = $this->img->left_margin; - $rm = $this->img->right_margin; - $tm = $this->img->top_margin; - $bm = $this->img->bottom_margin; - $this->img->CopyCanvasH($oldimage,$this->img->img, - $adj2 + round(($lm-$rm+$tm+$bm)/2), - $adj1 + round(($tm-$bm+$lm+$rm)/2), - $adj2 + round(($lm-$rm+$tm+$bm)/2), - $adj1 + round(($tm-$bm+$lm+$rm)/2), - $this->img->plotheight+1, - $this->img->plotwidth+1); - } - $this->img->Destroy(); - $this->img->SetCanvasH($oldimage); - } - - if( !$_csim ) { - $this->axis->Stroke($pos); - $this->axis->StrokeAngleLabels($pos,$this->iType); - } - - if( !$_csim ) { - $this->StrokePlotBox(); - $this->footer->Stroke($this->img); - - // The titles and legends never gets rotated so make sure - // that the angle is 0 before stroking them - $aa = $this->img->SetAngle(0); - $this->StrokeTitles(); - } - - for($i=0; $i < count($this->plots) ; ++$i ) { - $this->plots[$i]->Legend($this); - } - - $this->legend->Stroke($this->img); - - if( !$_csim ) { - - $this->StrokeTexts(); - $this->img->SetAngle($aa); - - // Draw an outline around the image map - if(_JPG_DEBUG) - $this->DisplayClientSideaImageMapAreas(); - - // If the filename is given as the special "__handle" - // then the image handler is returned and the image is NOT - // streamed back - if( $aStrokeFileName == _IMG_HANDLER ) { - return $this->img->img; - } - else { - // Finally stream the generated picture - $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); - } - } - } -} - - - -?> +numpoints = $n/2; + $this->coord = $aData; + $this->mark = new PlotMark(); + } + + function SetWeight($aWeight) { + $this->iLineWeight = $aWeight; + } + + function SetColor($aColor){ + $this->iColor = $aColor; + } + + function SetFillColor($aColor){ + $this->iFillColor = $aColor; + } + + function Max() { + $m = $this->coord[1]; + $i=1; + while( $i < $this->numpoints ) { + $m = max($m,$this->coord[2*$i+1]); + ++$i; + } + return $m; + } + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts=null) { + $this->csimtargets=$aTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + function SetLegend($aLegend,$aCSIM="",$aCSIMAlt="") { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimalt = $aCSIMAlt; + } + + // Private methods + + function Legend($aGraph) { + $color = $this->iColor ; + if( $this->legend != "" ) { + if( $this->iFillColor!='' ) { + $color = $this->iFillColor; + $aGraph->legend->Add($this->legend,$color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt); + } + else { + $aGraph->legend->Add($this->legend,$color,$this->mark,$this->line_style, + $this->legendcsimtarget,$this->legendcsimalt); + } + } + } + + function Stroke($img,$scale) { + + $i=0; + $p=array(); + $this->csimareas=''; + while($i < $this->numpoints) { + list($x1,$y1) = $scale->PTranslate($this->coord[2*$i],$this->coord[2*$i+1]); + $p[2*$i] = $x1; + $p[2*$i+1] = $y1; + + if( isset($this->csimtargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + $this->mark->SetCSIMAlt($this->csimalts[$i]); + $this->mark->SetCSIMAltVal($this->coord[2*$i], $this->coord[2*$i+1]); + $this->mark->Stroke($img,$x1,$y1); + $this->csimareas .= $this->mark->GetCSIMAreas(); + } + else { + $this->mark->Stroke($img,$x1,$y1); + } + + ++$i; + } + + if( $this->iFillColor != '' ) { + $img->SetColor($this->iFillColor); + $img->FilledPolygon($p); + } + $img->SetLineWeight($this->iLineWeight); + $img->SetColor($this->iColor); + $img->Polygon($p,$this->iFillColor!=''); + } +} + +//-------------------------------------------------------------------------- +// class PolarAxis +//-------------------------------------------------------------------------- +class PolarAxis extends Axis { + private $angle_step=15,$angle_color='lightgray',$angle_label_color='black'; + private $angle_fontfam=FF_FONT1,$angle_fontstyle=FS_NORMAL,$angle_fontsize=10; + private $angle_fontcolor = 'navy'; + private $gridminor_color='lightgray',$gridmajor_color='lightgray'; + private $show_minor_grid = false, $show_major_grid = true ; + private $show_angle_mark=true, $show_angle_grid=true, $show_angle_label=true; + private $angle_tick_len=3, $angle_tick_len2=3, $angle_tick_color='black'; + private $show_angle_tick=true; + private $radius_tick_color='black'; + + function __construct($img,$aScale) { + parent::__construct($img,$aScale); + } + + function ShowAngleDegreeMark($aFlg=true) { + $this->show_angle_mark = $aFlg; + } + + function SetAngleStep($aStep) { + $this->angle_step=$aStep; + } + + function HideTicks($aFlg=true,$aAngleFlg=true) { + parent::HideTicks($aFlg,$aFlg); + $this->show_angle_tick = !$aAngleFlg; + } + + function ShowAngleLabel($aFlg=true) { + $this->show_angle_label = $aFlg; + } + + function ShowGrid($aMajor=true,$aMinor=false,$aAngle=true) { + $this->show_minor_grid = $aMinor; + $this->show_major_grid = $aMajor; + $this->show_angle_grid = $aAngle ; + } + + function SetAngleFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->angle_fontfam = $aFontFam; + $this->angle_fontstyle = $aFontStyle; + $this->angle_fontsize = $aFontSize; + } + + function SetColor($aColor,$aRadColor='',$aAngleColor='') { + if( $aAngleColor == '' ) + $aAngleColor=$aColor; + parent::SetColor($aColor,$aRadColor); + $this->angle_fontcolor = $aAngleColor; + } + + function SetGridColor($aMajorColor,$aMinorColor='',$aAngleColor='') { + if( $aMinorColor == '' ) + $aMinorColor = $aMajorColor; + if( $aAngleColor == '' ) + $aAngleColor = $aMajorColor; + + $this->gridminor_color = $aMinorColor; + $this->gridmajor_color = $aMajorColor; + $this->angle_color = $aAngleColor; + } + + function SetTickColors($aRadColor,$aAngleColor='') { + $this->radius_tick_color = $aRadColor; + $this->angle_tick_color = $aAngleColor; + } + + // Private methods + function StrokeGrid($pos) { + $x = round($this->img->left_margin + $this->img->plotwidth/2); + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + + // Stroke the minor arcs + $pmin = array(); + $p = $this->scale->ticks->ticks_pos; + $n = count($p); + $i = 0; + $this->img->SetColor($this->gridminor_color); + while( $i < $n ) { + $r = $p[$i]-$x+1; + $pmin[]=$r; + if( $this->show_minor_grid ) { + $this->img->Circle($x,$pos,$r); + } + $i++; + } + + $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; + while( $r < $limit ) { + $off = $r; + $i=1; + $r = $off + round($p[$i]-$x+1); + while( $r < $limit && $i < $n ) { + $r = $off+$p[$i]-$x; + $pmin[]=$r; + if( $this->show_minor_grid ) { + $this->img->Circle($x,$pos,$r); + } + $i++; + } + } + + // Stroke the major arcs + if( $this->show_major_grid ) { + // First determine how many minor step on + // every major step. We have recorded the minor radius + // in pmin and use these values. This is done in order + // to avoid rounding errors if we were to recalculate the + // different major radius. + $pmaj = $this->scale->ticks->maj_ticks_pos; + $p = $this->scale->ticks->ticks_pos; + if( $this->scale->name == 'lin' ) { + $step=round(($pmaj[1] - $pmaj[0])/($p[1] - $p[0])); + } + else { + $step=9; + } + $n = round(count($pmin)/$step); + $i = 0; + $this->img->SetColor($this->gridmajor_color); + $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; + $off = $r; + $i=0; + $r = $pmin[$i*$step]; + while( $r < $limit && $i < $n ) { + $r = $pmin[$i*$step]; + $this->img->Circle($x,$pos,$r); + $i++; + } + } + + // Draw angles + if( $this->show_angle_grid ) { + $this->img->SetColor($this->angle_color); + $d = max($this->img->plotheight,$this->img->plotwidth)*1.4 ; + $a = 0; + $p = $this->scale->ticks->ticks_pos; + $start_radius = $p[1]-$x; + while( $a < 360 ) { + if( $a == 90 || $a == 270 ) { + // Make sure there are no rounding problem with + // exactly vertical lines + $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, + $pos-$start_radius*sin($a/180*M_PI), + $x+$start_radius*cos($a/180*M_PI)+1, + $pos-$d*sin($a/180*M_PI)); + + } + else { + $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, + $pos-$start_radius*sin($a/180*M_PI), + $x+$d*cos($a/180*M_PI), + $pos-$d*sin($a/180*M_PI)); + } + $a += $this->angle_step; + } + } + } + + function StrokeAngleLabels($pos,$type) { + + if( !$this->show_angle_label ) + return; + + $x0 = round($this->img->left_margin+$this->img->plotwidth/2)+1; + + $d = max($this->img->plotwidth,$this->img->plotheight)*1.42; + $a = $this->angle_step; + $t = new Text(); + $t->SetColor($this->angle_fontcolor); + $t->SetFont($this->angle_fontfam,$this->angle_fontstyle,$this->angle_fontsize); + $xright = $this->img->width - $this->img->right_margin; + $ytop = $this->img->top_margin; + $xleft = $this->img->left_margin; + $ybottom = $this->img->height - $this->img->bottom_margin; + $ha = 'left'; + $va = 'center'; + $w = $this->img->plotwidth/2; + $h = $this->img->plotheight/2; + $xt = $x0; $yt = $pos; + $margin=5; + + $tl = $this->angle_tick_len ; // Outer len + $tl2 = $this->angle_tick_len2 ; // Interior len + + $this->img->SetColor($this->angle_tick_color); + $rot90 = $this->img->a == 90 ; + + if( $type == POLAR_360 ) { + + // Corner angles of the four corners + $ca1 = atan($h/$w)/M_PI*180; + $ca2 = 180-$ca1; + $ca3 = $ca1+180; + $ca4 = 360-$ca1; + $end = 360; + + while( $a < $end ) { + $ca = cos($a/180*M_PI); + $sa = sin($a/180*M_PI); + $x = $d*$ca; + $y = $d*$sa; + $xt=1000;$yt=1000; + if( $a <= $ca1 || $a >= $ca4 ) { + $yt = $pos - $w * $y/$x; + $xt = $xright + $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'top'; + } + else { + $ha = 'left'; + $va = 'center'; + } + $x1=$xright-$tl2; $x2=$xright+$tl; + $y1=$y2=$yt; + } + elseif( $a > $ca1 && $a < $ca2 ) { + $xt = $x0 + $h * $x/$y; + $yt = $ytop - $margin; + if( $rot90 ) { + $ha = 'left'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'bottom'; + } + $y1=$ytop+$tl2;$y2=$ytop-$tl; + $x1=$x2=$xt; + } + elseif( $a >= $ca2 && $a <= $ca3 ) { + $yt = $pos + $w * $y/$x; + $xt = $xleft - $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'bottom'; + } + else { + $ha = 'right'; + $va = 'center'; + } + $x1=$xleft+$tl2;$x2=$xleft-$tl; + $y1=$y2=$yt; + } + else { + $xt = $x0 - $h * $x/$y; + $yt = $ybottom + $margin; + if( $rot90 ) { + $ha = 'right'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'top'; + } + $y1=$ybottom-$tl2;$y2=$ybottom+$tl; + $x1=$x2=$xt; + } + if( $a != 0 && $a != 180 ) { + $t->Align($ha,$va); + if( $this->scale->clockwise ) { + $t->Set(360-$a); + } + else { + $t->Set($a); + } + if( $this->show_angle_mark && $t->font_family > 4 ) { + $a .= SymChar::Get('degree'); + } + $t->Stroke($this->img,$xt,$yt); + if( $this->show_angle_tick ) { + $this->img->Line($x1,$y1,$x2,$y2); + } + } + $a += $this->angle_step; + } + } + else { + // POLAR_HALF + $ca1 = atan($h/$w*2)/M_PI*180; + $ca2 = 180-$ca1; + $end = 180; + while( $a < $end ) { + $ca = cos($a/180*M_PI); + $sa = sin($a/180*M_PI); + $x = $d*$ca; + $y = $d*$sa; + if( $a <= $ca1 ) { + $yt = $pos - $w * $y/$x; + $xt = $xright + $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'top'; + } + else { + $ha = 'left'; + $va = 'center'; + } + $x1=$xright-$tl2; $x2=$xright+$tl; + $y1=$y2=$yt; + } + elseif( $a > $ca1 && $a < $ca2 ) { + $xt = $x0 + 2*$h * $x/$y; + $yt = $ytop - $margin; + if( $rot90 ) { + $ha = 'left'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'bottom'; + } + $y1=$ytop+$tl2;$y2=$ytop-$tl; + $x1=$x2=$xt; + } + elseif( $a >= $ca2 ) { + $yt = $pos + $w * $y/$x; + $xt = $xleft - $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'bottom'; + } + else { + $ha = 'right'; + $va = 'center'; + } + $x1=$xleft+$tl2;$x2=$xleft-$tl; + $y1=$y2=$yt; + } + $t->Align($ha,$va); + if( $this->show_angle_mark && $t->font_family > 4 ) { + $a .= SymChar::Get('degree'); + } + $t->Set($a); + $t->Stroke($this->img,$xt,$yt); + if( $this->show_angle_tick ) { + $this->img->Line($x1,$y1,$x2,$y2); + } + $a += $this->angle_step; + } + } + } + + function Stroke($pos,$dummy=true) { + + $this->img->SetLineWeight($this->weight); + $this->img->SetColor($this->color); + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + if( !$this->hide_line ) { + $this->img->FilledRectangle($this->img->left_margin,$pos, + $this->img->width-$this->img->right_margin, + $pos+$this->weight-1); + } + $y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin; + if( $this->title_adjust=="high" ) { + $this->title->SetPos($this->img->width-$this->img->right_margin,$y,"right","top"); + } + elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" ) { + $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin, + $y,"center","top"); + } + elseif($this->title_adjust=="low") { + $this->title->SetPos($this->img->left_margin,$y,"left","top"); + } + else { + JpGraphError::RaiseL(17002,$this->title_adjust); + //('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); + } + + + if (!$this->hide_labels) { + $this->StrokeLabels($pos,false); + } + $this->img->SetColor($this->radius_tick_color); + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + + // + // Mirror the positions for the left side of the scale + // + $mid = 2*($this->img->left_margin+$this->img->plotwidth/2); + $n = count($this->scale->ticks->ticks_pos); + $i=0; + while( $i < $n ) { + $this->scale->ticks->ticks_pos[$i] = + $mid-$this->scale->ticks->ticks_pos[$i] ; + ++$i; + } + + $n = count($this->scale->ticks->maj_ticks_pos); + $i=0; + while( $i < $n ) { + $this->scale->ticks->maj_ticks_pos[$i] = + $mid-$this->scale->ticks->maj_ticks_pos[$i] ; + ++$i; + } + + $n = count($this->scale->ticks->maj_ticklabels_pos); + $i=1; + while( $i < $n ) { + $this->scale->ticks->maj_ticklabels_pos[$i] = + $mid-$this->scale->ticks->maj_ticklabels_pos[$i] ; + ++$i; + } + + // Draw the left side of the scale + $n = count($this->scale->ticks->ticks_pos); + $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMinTickAbsSize(); + + + // Minor ticks + if( ! $this->scale->ticks->supress_minor_tickmarks ) { + $i=1; + while( $i < $n/2 ) { + $x = round($this->scale->ticks->ticks_pos[$i]) ; + $this->img->Line($x,$pos,$x,$yu); + ++$i; + } + } + + $n = count($this->scale->ticks->maj_ticks_pos); + $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMajTickAbsSize(); + + + // Major ticks + if( ! $this->scale->ticks->supress_tickmarks ) { + $i=1; + while( $i < $n/2 ) { + $x = round($this->scale->ticks->maj_ticks_pos[$i]) ; + $this->img->Line($x,$pos,$x,$yu); + ++$i; + } + } + if (!$this->hide_labels) { + $this->StrokeLabels($pos,false); + } + $this->title->Stroke($this->img); + } +} + +class PolarScale extends LinearScale { + private $graph; + public $clockwise=false; + + function __construct($aMax,$graph,$aClockwise) { + parent::__construct(0,$aMax,'x'); + $this->graph = $graph; + $this->clockwise = $aClockwise; + } + + function SetClockwise($aFlg) { + $this->clockwise = $aFlg; + } + + function _Translate($v) { + return parent::Translate($v); + } + + function PTranslate($aAngle,$aRad) { + + $m = $this->scale[1]; + $w = $this->graph->img->plotwidth/2; + $aRad = $aRad/$m*$w; + + $a = $aAngle/180 * M_PI; + if( $this->clockwise ) { + $a = 2*M_PI-$a; + } + + $x = cos($a) * $aRad; + $y = sin($a) * $aRad; + + $x += $this->_Translate(0); + + if( $this->graph->iType == POLAR_360 ) { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; + } + else { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; + } + return array($x,$y); + } +} + +class PolarLogScale extends LogScale { + private $graph; + public $clockwise=false; + + function __construct($aMax,$graph,$aClockwise=false) { + parent::__construct(0,$aMax,'x'); + $this->graph = $graph; + $this->ticks->SetLabelLogType(LOGLABELS_MAGNITUDE); + $this->clockwise = $aClockwise; + + } + + function SetClockwise($aFlg) { + $this->clockwise = $aFlg; + } + + function PTranslate($aAngle,$aRad) { + + if( $aRad == 0 ) + $aRad = 1; + $aRad = log10($aRad); + $m = $this->scale[1]; + $w = $this->graph->img->plotwidth/2; + $aRad = $aRad/$m*$w; + + $a = $aAngle/180 * M_PI; + if( $this->clockwise ) { + $a = 2*M_PI-$a; + } + + $x = cos( $a ) * $aRad; + $y = sin( $a ) * $aRad; + + $x += $w+$this->graph->img->left_margin;//$this->_Translate(0); + if( $this->graph->iType == POLAR_360 ) { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; + } + else { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; + } + return array($x,$y); + } +} + +class PolarGraph extends Graph { + public $scale; + public $axis; + public $iType=POLAR_360; + private $iClockwise=false; + + function __construct($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { + parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline) ; + $this->SetDensity(TICKD_DENSE); + $this->SetBox(); + $this->SetMarginColor('white'); + } + + function SetDensity($aDense) { + $this->SetTickDensity(TICKD_NORMAL,$aDense); + } + + function SetClockwise($aFlg) { + $this->scale->SetClockwise($aFlg); + } + + function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { + $adj = ($this->img->height - $this->img->width)/2; + $this->SetAngle(90); + $lm2 = -$adj + ($lm-$rm+$tm+$bm)/2; + $rm2 = -$adj + (-$lm+$rm+$tm+$bm)/2; + $tm2 = $adj + ($tm-$bm+$lm+$rm)/2; + $bm2 = $adj + (-$tm+$bm+$lm+$rm)/2; + $this->SetMargin($lm2, $rm2, $tm2, $bm2); + $this->axis->SetLabelAlign('right','center'); + } + + function SetScale($aScale,$rmax=0,$dummy1=1,$dummy2=1,$dummy3=1) { + if( $aScale == 'lin' ) { + $this->scale = new PolarScale($rmax,$this,$this->iClockwise); + } + elseif( $aScale == 'log' ) { + $this->scale = new PolarLogScale($rmax,$this,$this->iClockwise); + } + else { + JpGraphError::RaiseL(17004);//('Unknown scale type for polar graph. Must be "lin" or "log"'); + } + + $this->axis = new PolarAxis($this->img,$this->scale); + $this->SetMargin(40,40,50,40); + } + + function SetType($aType) { + $this->iType = $aType; + } + + function SetPlotSize($w,$h) { + $this->SetMargin(($this->img->width-$w)/2,($this->img->width-$w)/2, + ($this->img->height-$h)/2,($this->img->height-$h)/2); + } + + // Private methods + function GetPlotsMax() { + $n = count($this->plots); + $m = $this->plots[0]->Max(); + $i=1; + while($i < $n) { + $m = max($this->plots[$i]->Max(),$m); + ++$i; + } + return $m; + } + + function Stroke($aStrokeFileName="") { + + // Start by adjusting the margin so that potential titles will fit. + $this->AdjustMarginsForTitles(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + //Check if we should autoscale axis + if( !$this->scale->IsSpecified() && count($this->plots)>0 ) { + $max = $this->GetPlotsMax(); + $t1 = $this->img->plotwidth; + $this->img->plotwidth /= 2; + $t2 = $this->img->left_margin; + $this->img->left_margin += $this->img->plotwidth+1; + $this->scale->AutoScale($this->img,0,$max, + $this->img->plotwidth/$this->xtick_factor/2); + $this->img->plotwidth = $t1; + $this->img->left_margin = $t2; + } + else { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + //$min = 0; + $max = $this->scale->scale[1]; + $t1 = $this->img->plotwidth; + $this->img->plotwidth /= 2; + $t2 = $this->img->left_margin; + $this->img->left_margin += $this->img->plotwidth+1; + $this->scale->AutoScale($this->img,0,$max, + $this->img->plotwidth/$this->xtick_factor/2); + $this->img->plotwidth = $t1; + $this->img->left_margin = $t2; + } + + if( $this->iType == POLAR_180 ) { + $pos = $this->img->height - $this->img->bottom_margin; + } + else { + $pos = $this->img->plotheight/2 + $this->img->top_margin; + } + + if( !$_csim ) { + $this->StrokePlotArea(); + } + + $this->iDoClipping = true; + + if( $this->iDoClipping ) { + $oldimage = $this->img->CloneCanvasH(); + } + + if( !$_csim ) { + $this->axis->StrokeGrid($pos); + } + + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->scale); + } + + + if( $this->iDoClipping ) { + // Clipping only supports graphs at 0 and 90 degrees + if( $this->img->a == 0 ) { + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->left_margin,$this->img->top_margin, + $this->img->left_margin,$this->img->top_margin, + $this->img->plotwidth+1,$this->img->plotheight+1); + } + elseif( $this->img->a == 90 ) { + $adj1 = round(($this->img->height - $this->img->width)/2); + $adj2 = round(($this->img->width - $this->img->height)/2); + $lm = $this->img->left_margin; + $rm = $this->img->right_margin; + $tm = $this->img->top_margin; + $bm = $this->img->bottom_margin; + $this->img->CopyCanvasH($oldimage,$this->img->img, + $adj2 + round(($lm-$rm+$tm+$bm)/2), + $adj1 + round(($tm-$bm+$lm+$rm)/2), + $adj2 + round(($lm-$rm+$tm+$bm)/2), + $adj1 + round(($tm-$bm+$lm+$rm)/2), + $this->img->plotheight+1, + $this->img->plotwidth+1); + } + $this->img->Destroy(); + $this->img->SetCanvasH($oldimage); + } + + if( !$_csim ) { + $this->axis->Stroke($pos); + $this->axis->StrokeAngleLabels($pos,$this->iType); + } + + if( !$_csim ) { + $this->StrokePlotBox(); + $this->footer->Stroke($this->img); + + // The titles and legends never gets rotated so make sure + // that the angle is 0 before stroking them + $aa = $this->img->SetAngle(0); + $this->StrokeTitles(); + } + + for($i=0; $i < count($this->plots) ; ++$i ) { + $this->plots[$i]->Legend($this); + } + + $this->legend->Stroke($this->img); + + if( !$_csim ) { + + $this->StrokeTexts(); + $this->img->SetAngle($aa); + + // Draw an outline around the image map + if(_JPG_DEBUG) + $this->DisplayClientSideaImageMapAreas(); + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + } + } + } +} + + + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_radar.php b/ext/jpgraph-3.0.7/src/jpgraph_radar.php index c71ffaf..aa4b215 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_radar.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_radar.php @@ -1,861 +1,861 @@ -GetMinVal(); - $limit = $aScale->GetMaxVal(); - $nextMajor = 10*$start; - $step = $nextMajor / 10.0; - $count=1; - - $ticklen_maj=5; - $dx_maj=round(sin($aAxisAngle)*$ticklen_maj); - $dy_maj=round(cos($aAxisAngle)*$ticklen_maj); - $ticklen_min=3; - $dx_min=round(sin($aAxisAngle)*$ticklen_min); - $dy_min=round(cos($aAxisAngle)*$ticklen_min); - - $aMajPos=array(); - $aMajLabel=array(); - - if( $this->supress_first ) { - $aMajLabel[] = ''; - } - else { - $aMajLabel[]=$start; - } - - $yr=$aScale->RelTranslate($start); - $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; - $yt=$aPos-round($yr*sin($aAxisAngle)); - $aMajPos[]=$xt+2*$dx_maj; - $aMajPos[]=$yt-$aImg->GetFontheight()/2; - $grid[]=$xt; - $grid[]=$yt; - - $aImg->SetLineWeight($this->weight); - - for($y=$start; $y<=$limit; $y+=$step,++$count ) { - $yr=$aScale->RelTranslate($y); - $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; - $yt=$aPos-round($yr*sin($aAxisAngle)); - if( $count % 10 == 0 ) { - $grid[]=$xt; - $grid[]=$yt; - $aMajPos[]=$xt+2*$dx_maj; - $aMajPos[]=$yt-$aImg->GetFontheight()/2; - if( !$this->supress_tickmarks ) { - if( $this->majcolor != '' ) { - $aImg->PushColor($this->majcolor); - } - $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj); - if( $this->majcolor != '' ) { - $aImg->PopColor(); - } - } - if( $this->label_formfunc != '' ) { - $f=$this->label_formfunc; - $l = call_user_func($f,$nextMajor); - } - else { - $l = $nextMajor; - } - - $aMajLabel[]=$l; - $nextMajor *= 10; - $step *= 10; - $count=1; - } - else { - if( !$this->supress_minor_tickmarks ) { - if( $this->mincolor != '' ) { - $aImg->PushColor($this->mincolor); - } - $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min); - if( $this->mincolor != '' ) { - $aImg->PopColor(); - } - } - } - } - } -} - -//=================================================== -// CLASS RadarLinear -// Description: Linear ticks -//=================================================== -class RadarLinearTicks extends Ticks { - - private $minor_step=1, $major_step=2; - private $xlabel_offset=0,$xtick_offset=0; - - function __construct() { - // Empty - } - - // Return major step size in world coordinates - function GetMajor() { - return $this->major_step; - } - - // Return minor step size in world coordinates - function GetMinor() { - return $this->minor_step; - } - - // Set Minor and Major ticks (in world coordinates) - function Set($aMajStep,$aMinStep=false) { - if( $aMinStep==false ) { - $aMinStep=$aMajStep; - } - - if( $aMajStep <= 0 || $aMinStep <= 0 ) { - JpGraphError::RaiseL(25064); - //JpGraphError::Raise(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); - } - - $this->major_step=$aMajStep; - $this->minor_step=$aMinStep; - $this->is_set = true; - } - - function Stroke($aImg,&$grid,$aPos,$aAxisAngle,$aScale,&$aMajPos,&$aMajLabel) { - // Prepare to draw linear ticks - $maj_step_abs = abs($aScale->scale_factor*$this->major_step); - $min_step_abs = abs($aScale->scale_factor*$this->minor_step); - $nbrmaj = round($aScale->world_abs_size/$maj_step_abs); - $nbrmin = round($aScale->world_abs_size/$min_step_abs); - $skip = round($nbrmin/$nbrmaj); // Don't draw minor on top of major - - // Draw major ticks - $ticklen2=$this->major_abs_size; - $dx=round(sin($aAxisAngle)*$ticklen2); - $dy=round(cos($aAxisAngle)*$ticklen2); - $label=$aScale->scale[0]+$this->major_step; - - $aImg->SetLineWeight($this->weight); - - $aMajPos = array(); - $aMajLabel = array(); - - for($i=1; $i<=$nbrmaj; ++$i) { - $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; - $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle)); - - if( $this->label_formfunc != '' ) { - $f=$this->label_formfunc; - $l = call_user_func($f,$label); - } - else { - $l = $label; - } - - $aMajLabel[]=$l; - $label += $this->major_step; - $grid[]=$xt; - $grid[]=$yt; - $aMajPos[($i-1)*2]=$xt+2*$dx; - $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2; - if( !$this->supress_tickmarks ) { - if( $this->majcolor != '' ) { - $aImg->PushColor($this->majcolor); - } - $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); - if( $this->majcolor != '' ) { - $aImg->PopColor(); - } - } - } - - // Draw minor ticks - $ticklen2=$this->minor_abs_size; - $dx=round(sin($aAxisAngle)*$ticklen2); - $dy=round(cos($aAxisAngle)*$ticklen2); - if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { - if( $this->mincolor != '' ) { - $aImg->PushColor($this->mincolor); - } - for($i=1; $i<=$nbrmin; ++$i) { - if( ($i % $skip) == 0 ) { - continue; - } - $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; - $yt=$aPos-round($i*$min_step_abs*sin($aAxisAngle)); - $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); - } - if( $this->mincolor != '' ) { - $aImg->PopColor(); - } - } - } -} - - -//=================================================== -// CLASS RadarAxis -// Description: Implements axis for the radar graph -//=================================================== -class RadarAxis extends AxisPrototype { - public $title=null; - private $title_color='navy'; - private $len=0; - - function __construct($img,$aScale,$color=array(0,0,0)) { - parent::__construct($img,$aScale,$color); - $this->len = $img->plotheight; - $this->title = new Text(); - $this->title->SetFont(FF_FONT1,FS_BOLD); - $this->color = array(0,0,0); - } - - // Stroke the axis - // $pos = Vertical position of axis - // $aAxisAngle = Axis angle - // $grid = Returns an array with positions used to draw the grid - // $lf = Label flag, TRUE if the axis should have labels - function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) { - $this->img->SetColor($this->color); - - // Determine end points for the axis - $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]); - $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle)); - - // Draw axis - $this->img->SetColor($this->color); - $this->img->SetLineWeight($this->weight); - if( !$this->hide ) { - $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y); - } - - $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel); - $ncolor=0; - if( isset($this->ticks_label_colors) ) { - $ncolor=count($this->ticks_label_colors); - } - - // Draw labels - if( $lf && !$this->hide ) { - $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); - $this->img->SetTextAlign('left','top'); - $this->img->SetColor($this->label_color); - - // majpos contains (x,y) coordinates for labels - if( ! $this->hide_labels ) { - $n = floor(count($majpos)/2); - for($i=0; $i < $n; ++$i) { - // Set specific label color if specified - if( $ncolor > 0 ) { - $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); - } - - if( $this->ticks_label != null && isset($this->ticks_label[$i]) ) { - $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]); - } - else { - $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]); - } - } - } - } - $this->_StrokeAxisTitle($pos,$aAxisAngle,$title); - } - - function _StrokeAxisTitle($pos,$aAxisAngle,$title) { - $this->title->Set($title); - $marg=6+$this->title->margin; - $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]); - $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle)); - - // Position the axis title. - // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text - // that intersects with the extension of the corresponding axis. The code looks a little - // bit messy but this is really the only way of having a reasonable position of the - // axis titles. - if( $this->title->iWordwrap > 0 ) { - $title = wordwrap($title,$this->title->iWordwrap,"\n"); - } - - $h=$this->img->GetTextHeight($title)*1.2; - $w=$this->img->GetTextWidth($title)*1.2; - - while( $aAxisAngle > 2*M_PI ) - $aAxisAngle -= 2*M_PI; - - // Around 3 a'clock - if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=-0.15; // Small trimming to make the dist to the axis more even - - // Around 12 a'clock - if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; - - // Around 9 a'clock - if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1; - - // Around 6 a'clock - if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI); - - if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI; - if( $aAxisAngle<=M_PI/12 ) $dy=(0.5-$aAxisAngle*2/M_PI); - if( $aAxisAngle<=M_PI/4 && $aAxisAngle > M_PI/12) $dy=(1-$aAxisAngle*2/M_PI); - if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1; - if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI); - if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0; - - if( !$this->hide ) { - $this->title->Stroke($this->img,$xt-$dx*$w,$yt-$dy*$h,$title); - } - } - -} // Class - - -//=================================================== -// CLASS RadarGrid -// Description: Draws grid for the radar graph -//=================================================== -class RadarGrid { //extends Grid { - private $type='solid'; - private $grid_color='#DDDDDD'; - private $show=false, $weight=1; - - function __construct() { - // Empty - } - - function SetColor($aMajColor) { - $this->grid_color = $aMajColor; - } - - function SetWeight($aWeight) { - $this->weight=$aWeight; - } - - // Specify if grid should be dashed, dotted or solid - function SetLineStyle($aType) { - $this->type = $aType; - } - - // Decide if both major and minor grid should be displayed - function Show($aShowMajor=true) { - $this->show=$aShowMajor; - } - - function Stroke($img,$grid) { - if( !$this->show ) { - return; - } - - $nbrticks = count($grid[0])/2; - $nbrpnts = count($grid); - $img->SetColor($this->grid_color); - $img->SetLineWeight($this->weight); - - for($i=0; $i<$nbrticks; ++$i) { - for($j=0; $j<$nbrpnts; ++$j) { - $pnts[$j*2]=$grid[$j][$i*2]; - $pnts[$j*2+1]=$grid[$j][$i*2+1]; - } - for($k=0; $k<$nbrpnts; ++$k ){ - $l=($k+1)%$nbrpnts; - if( $this->type == 'solid' ) - $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]); - elseif( $this->type == 'dotted' ) - $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6); - elseif( $this->type == 'dashed' ) - $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4); - elseif( $this->type == 'longdashed' ) - $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6); - } - $pnts=array(); - } - } -} // Class - - -//=================================================== -// CLASS RadarPlot -// Description: Plot a radarplot -//=================================================== -class RadarPlot { - public $mark=null; - public $legend=''; - public $legendcsimtarget=''; - public $legendcsimalt=''; - public $csimtargets=array(); // Array of targets for CSIM - public $csimareas=""; // Resultant CSIM area tags - public $csimalts=null; // ALT:s for corresponding target - private $data=array(); - private $fill=false, $fill_color=array(200,170,180); - private $color=array(0,0,0); - private $weight=1; - private $linestyle='solid'; - - //--------------- - // CONSTRUCTOR - function __construct($data) { - $this->data = $data; - $this->mark = new PlotMark(); - } - - function Min() { - return Min($this->data); - } - - function Max() { - return Max($this->data); - } - - function SetLegend($legend) { - $this->legend=$legend; - } - - function SetLineStyle($aStyle) { - $this->linestyle=$aStyle; - } - - function SetLineWeight($w) { - $this->weight=$w; - } - - function SetFillColor($aColor) { - $this->fill_color = $aColor; - $this->fill = true; - } - - function SetFill($f=true) { - $this->fill = $f; - } - - function SetColor($aColor,$aFillColor=false) { - $this->color = $aColor; - if( $aFillColor ) { - $this->SetFillColor($aFillColor); - $this->fill = true; - } - } - - // Set href targets for CSIM - function SetCSIMTargets($aTargets,$aAlts=null) { - $this->csimtargets=$aTargets; - $this->csimalts=$aAlts; - } - - // Get all created areas - function GetCSIMareas() { - return $this->csimareas; - } - - function Stroke($img, $pos, $scale, $startangle) { - $nbrpnts = count($this->data); - $astep=2*M_PI/$nbrpnts; - $a=$startangle; - - for($i=0; $i<$nbrpnts; ++$i) { - - // Rotate each non null point to the correct axis-angle - $cs=$scale->RelTranslate($this->data[$i]); - $x=round($cs*cos($a)+$scale->scale_abs[0]); - $y=round($pos-$cs*sin($a)); - - $pnts[$i*2]=$x; - $pnts[$i*2+1]=$y; - - // If the next point is null then we draw this polygon segment - // to the center, skip the next and draw the next segment from - // the center up to the point on the axis with the first non-null - // value and continues from that point. Some additoinal logic is necessary - // to handle the boundary conditions - if( $i < $nbrpnts-1 ) { - if( is_null($this->data[$i+1]) ) { - $cs = 0; - $x=round($cs*cos($a)+$scale->scale_abs[0]); - $y=round($pos-$cs*sin($a)); - $pnts[$i*2]=$x; - $pnts[$i*2+1]=$y; - $a += $astep; - } - } - - $a += $astep; - } - - if( $this->fill ) { - $img->SetColor($this->fill_color); - $img->FilledPolygon($pnts); - } - - $img->SetLineWeight($this->weight); - $img->SetColor($this->color); - $img->SetLineStyle($this->linestyle); - $pnts[] = $pnts[0]; - $pnts[] = $pnts[1]; - $img->Polygon($pnts); - $img->SetLineStyle('solid'); // Reset line style to default - - // Add plotmarks on top - if( $this->mark->show ) { - for($i=0; $i < $nbrpnts; ++$i) { - if( isset($this->csimtargets[$i]) ) { - $this->mark->SetCSIMTarget($this->csimtargets[$i]); - $this->mark->SetCSIMAlt($this->csimalts[$i]); - $this->mark->SetCSIMAltVal($pnts[$i*2], $pnts[$i*2+1]); - $this->mark->Stroke($img, $pnts[$i*2], $pnts[$i*2+1]); - $this->csimareas .= $this->mark->GetCSIMAreas(); - } - else { - $this->mark->Stroke($img,$pnts[$i*2],$pnts[$i*2+1]); - } - } - } - - } - - function GetCount() { - return count($this->data); - } - - function Legend($graph) { - if( $this->legend == '' ) { - return; - } - if( $this->fill ) { - $graph->legend->Add($this->legend,$this->fill_color,$this->mark); - } else { - $graph->legend->Add($this->legend,$this->color,$this->mark); - } - } - -} // Class - -//=================================================== -// CLASS RadarGraph -// Description: Main container for a radar graph -//=================================================== -class RadarGraph extends Graph { - public $grid,$axis=null; - private $posx,$posy; - private $len; - private $axis_title=null; - - function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { - parent::__construct($width,$height,$cachedName,$timeout,$inline); - $this->posx = $width/2; - $this->posy = $height/2; - $this->len = min($width,$height)*0.35; - $this->SetColor(array(255,255,255)); - $this->SetTickDensity(TICKD_NORMAL); - $this->SetScale('lin'); - $this->SetGridDepth(DEPTH_FRONT); - } - - function HideTickMarks($aFlag=true) { - $this->axis->scale->ticks->SupressTickMarks($aFlag); - } - - function ShowMinorTickmarks($aFlag=true) { - $this->yscale->ticks->SupressMinorTickMarks(!$aFlag); - } - - function SetScale($axtype,$ymin=1,$ymax=1,$dummy1=null,$dumy2=null) { - if( $axtype != 'lin' && $axtype != 'log' ) { - JpGraphError::RaiseL(18003,$axtype); - //("Illegal scale for radarplot ($axtype). Must be \"lin\" or \"log\""); - } - if( $axtype == 'lin' ) { - $this->yscale = new LinearScale($ymin,$ymax); - $this->yscale->ticks = new RadarLinearTicks(); - $this->yscale->ticks->SupressMinorTickMarks(); - } - elseif( $axtype == 'log' ) { - $this->yscale = new LogScale($ymin,$ymax); - $this->yscale->ticks = new RadarLogTicks(); - } - - $this->axis = new RadarAxis($this->img,$this->yscale); - $this->grid = new RadarGrid(); - } - - function SetSize($aSize) { - if( $aSize < 0.1 || $aSize>1 ) { - JpGraphError::RaiseL(18004,$aSize); - //("Radar Plot size must be between 0.1 and 1. (Your value=$s)"); - } - $this->len=min($this->img->width,$this->img->height)*$aSize/2; - } - - function SetPlotSize($aSize) { - $this->SetSize($aSize); - } - - function SetTickDensity($densy=TICKD_NORMAL,$dummy1=null) { - $this->ytick_factor=25; - switch( $densy ) { - case TICKD_DENSE: - $this->ytick_factor=12; - break; - case TICKD_NORMAL: - $this->ytick_factor=25; - break; - case TICKD_SPARSE: - $this->ytick_factor=40; - break; - case TICKD_VERYSPARSE: - $this->ytick_factor=70; - break; - default: - JpGraphError::RaiseL(18005,$densy); - //("RadarPlot Unsupported Tick density: $densy"); - } - } - - function SetPos($px,$py=0.5) { - $this->SetCenter($px,$py); - } - - function SetCenter($px,$py=0.5) { - if( $px >= 0 && $px <= 1 ) { - $this->posx = $this->img->width*$px; - } - else { - $this->posx = $px; - } - if( $py >= 0 && $py <= 1 ) { - $this->posy = $this->img->height*$py; - } - else { - $this->posy = $py; - } - } - - function SetColor($aColor) { - $this->SetMarginColor($aColor); - } - - function SetTitles($aTitleArray) { - $this->axis_title = $aTitleArray; - } - - function Add($aPlot) { - if( $aPlot == null ) { - JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); - } - if( is_array($aPlot) && count($aPlot) > 0 ) { - $cl = $aPlot[0]; - } - else { - $cl = $aPlot; - } - - if( $cl instanceof Text ) $this->AddText($aPlot); - elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot); - else { - $this->plots[] = $aPlot; - } - } - - function GetPlotsYMinMax($aPlots) { - $min=$aPlots[0]->Min(); - $max=$aPlots[0]->Max(); - foreach( $this->plots as $p ) { - $max=max($max,$p->Max()); - $min=min($min,$p->Min()); - } - if( $min < 0 ) { - JpGraphError::RaiseL(18006,$min); - //("Minimum data $min (Radar plots should only be used when all data points > 0)"); - } - return array($min,$max); - } - - function StrokeIcons() { - if( $this->iIcons != null ) { - $n = count($this->iIcons); - for( $i=0; $i < $n; ++$i ) { - $this->iIcons[$i]->Stroke($this->img); - } - } - } - - function StrokeTexts() { - if( $this->texts != null ) { - $n = count($this->texts); - for( $i=0; $i < $n; ++$i ) { - $this->texts[$i]->Stroke($this->img); - } - } - } - - // Stroke the Radar graph - function Stroke($aStrokeFileName='') { - - // If the filename is the predefined value = '_csim_special_' - // we assume that the call to stroke only needs to do enough - // to correctly generate the CSIM maps. - // We use this variable to skip things we don't strictly need - // to do to generate the image map to improve performance - // a best we can. Therefor you will see a lot of tests !$_csim in the - // code below. - $_csim = ( $aStrokeFileName === _CSIM_SPECIALFILE ); - - // We need to know if we have stroked the plot in the - // GetCSIMareas. Otherwise the CSIM hasn't been generated - // and in the case of GetCSIM called before stroke to generate - // CSIM without storing an image to disk GetCSIM must call Stroke. - $this->iHasStroked = true; - - $n = count($this->plots); - // Set Y-scale - - if( !$this->yscale->IsSpecified() && count($this->plots) > 0 ) { - list($min,$max) = $this->GetPlotsYMinMax($this->plots); - $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor); - } - elseif( $this->yscale->IsSpecified() && - ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { - - // The tick calculation will use the user suplied min/max values to determine - // the ticks. If auto_ticks is false the exact user specifed min and max - // values will be used for the scale. - // If auto_ticks is true then the scale might be slightly adjusted - // so that the min and max values falls on an even major step. - $min = $this->yscale->scale[0]; - $max = $this->yscale->scale[1]; - $this->yscale->AutoScale($this->img,$min,$max, - $this->len/$this->ytick_factor, - $this->yscale->auto_ticks); - } - - // Set start position end length of scale (in absolute pixels) - $this->yscale->SetConstants($this->posx,$this->len); - - // We need as many axis as there are data points - $nbrpnts=$this->plots[0]->GetCount(); - - // If we have no titles just number the axis 1,2,3,... - if( $this->axis_title==null ) { - for($i=0; $i < $nbrpnts; ++$i ) { - $this->axis_title[$i] = $i+1; - } - } - elseif( count($this->axis_title) < $nbrpnts) { - JpGraphError::RaiseL(18007); - // ("Number of titles does not match number of points in plot."); - } - for( $i=0; $i < $n; ++$i ) { - if( $nbrpnts != $this->plots[$i]->GetCount() ) { - JpGraphError::RaiseL(18008); - //("Each radar plot must have the same number of data points."); - } - } - - if( !$_csim ) { - if( $this->background_image != '' ) { - $this->StrokeFrameBackground(); - } - else { - $this->StrokeFrame(); - $this->StrokeBackgroundGrad(); - } - } - $astep=2*M_PI/$nbrpnts; - - if( !$_csim ) { - if( $this->iIconDepth == DEPTH_BACK ) { - $this->StrokeIcons(); - } - - - // Prepare legends - for($i=0; $i < $n; ++$i) { - $this->plots[$i]->Legend($this); - } - $this->legend->Stroke($this->img); - $this->footer->Stroke($this->img); - } - - if( !$_csim ) { - if( $this->grid_depth == DEPTH_BACK ) { - // Draw axis and grid - for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { - $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); - } - $this->grid->Stroke($this->img,$grid); - } - if( $this->iIconDepth == DEPTH_BACK ) { - $this->StrokeIcons(); - } - - } - - // Plot points - $a=M_PI/2; - for($i=0; $i < $n; ++$i ) { - $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a); - } - - if( !$_csim ) { - if( $this->grid_depth != DEPTH_BACK ) { - // Draw axis and grid - for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { - $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); - } - $this->grid->Stroke($this->img,$grid); - } - - $this->StrokeTitles(); - $this->StrokeTexts(); - if( $this->iIconDepth == DEPTH_FRONT ) { - $this->StrokeIcons(); - } - } - - // Should we do any final image transformation - if( $this->iImgTrans && !$_csim ) { - if( !class_exists('ImgTrans',false) ) { - require_once('jpgraph_imgtrans.php'); - } - - $tform = new ImgTrans($this->img->img); - $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, - $this->iImgTransDirection,$this->iImgTransHighQ, - $this->iImgTransMinSize,$this->iImgTransFillColor, - $this->iImgTransBorder); - } - - if( !$_csim ) { - // If the filename is given as the special "__handle" - // then the image handler is returned and the image is NOT - // streamed back - if( $aStrokeFileName == _IMG_HANDLER ) { - return $this->img->img; - } - else { - // Finally stream the generated picture - $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); - } - } - } -} // Class - -/* EOF */ -?> +GetMinVal(); + $limit = $aScale->GetMaxVal(); + $nextMajor = 10*$start; + $step = $nextMajor / 10.0; + $count=1; + + $ticklen_maj=5; + $dx_maj=round(sin($aAxisAngle)*$ticklen_maj); + $dy_maj=round(cos($aAxisAngle)*$ticklen_maj); + $ticklen_min=3; + $dx_min=round(sin($aAxisAngle)*$ticklen_min); + $dy_min=round(cos($aAxisAngle)*$ticklen_min); + + $aMajPos=array(); + $aMajLabel=array(); + + if( $this->supress_first ) { + $aMajLabel[] = ''; + } + else { + $aMajLabel[]=$start; + } + + $yr=$aScale->RelTranslate($start); + $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($yr*sin($aAxisAngle)); + $aMajPos[]=$xt+2*$dx_maj; + $aMajPos[]=$yt-$aImg->GetFontheight()/2; + $grid[]=$xt; + $grid[]=$yt; + + $aImg->SetLineWeight($this->weight); + + for($y=$start; $y<=$limit; $y+=$step,++$count ) { + $yr=$aScale->RelTranslate($y); + $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($yr*sin($aAxisAngle)); + if( $count % 10 == 0 ) { + $grid[]=$xt; + $grid[]=$yt; + $aMajPos[]=$xt+2*$dx_maj; + $aMajPos[]=$yt-$aImg->GetFontheight()/2; + if( !$this->supress_tickmarks ) { + if( $this->majcolor != '' ) { + $aImg->PushColor($this->majcolor); + } + $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj); + if( $this->majcolor != '' ) { + $aImg->PopColor(); + } + } + if( $this->label_formfunc != '' ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$nextMajor); + } + else { + $l = $nextMajor; + } + + $aMajLabel[]=$l; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_minor_tickmarks ) { + if( $this->mincolor != '' ) { + $aImg->PushColor($this->mincolor); + } + $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min); + if( $this->mincolor != '' ) { + $aImg->PopColor(); + } + } + } + } + } +} + +//=================================================== +// CLASS RadarLinear +// Description: Linear ticks +//=================================================== +class RadarLinearTicks extends Ticks { + + private $minor_step=1, $major_step=2; + private $xlabel_offset=0,$xtick_offset=0; + + function __construct() { + // Empty + } + + // Return major step size in world coordinates + function GetMajor() { + return $this->major_step; + } + + // Return minor step size in world coordinates + function GetMinor() { + return $this->minor_step; + } + + // Set Minor and Major ticks (in world coordinates) + function Set($aMajStep,$aMinStep=false) { + if( $aMinStep==false ) { + $aMinStep=$aMajStep; + } + + if( $aMajStep <= 0 || $aMinStep <= 0 ) { + JpGraphError::RaiseL(25064); + //JpGraphError::Raise(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); + } + + $this->major_step=$aMajStep; + $this->minor_step=$aMinStep; + $this->is_set = true; + } + + function Stroke($aImg,&$grid,$aPos,$aAxisAngle,$aScale,&$aMajPos,&$aMajLabel) { + // Prepare to draw linear ticks + $maj_step_abs = abs($aScale->scale_factor*$this->major_step); + $min_step_abs = abs($aScale->scale_factor*$this->minor_step); + $nbrmaj = round($aScale->world_abs_size/$maj_step_abs); + $nbrmin = round($aScale->world_abs_size/$min_step_abs); + $skip = round($nbrmin/$nbrmaj); // Don't draw minor on top of major + + // Draw major ticks + $ticklen2=$this->major_abs_size; + $dx=round(sin($aAxisAngle)*$ticklen2); + $dy=round(cos($aAxisAngle)*$ticklen2); + $label=$aScale->scale[0]+$this->major_step; + + $aImg->SetLineWeight($this->weight); + + $aMajPos = array(); + $aMajLabel = array(); + + for($i=1; $i<=$nbrmaj; ++$i) { + $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle)); + + if( $this->label_formfunc != '' ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$label); + } + else { + $l = $label; + } + + $aMajLabel[]=$l; + $label += $this->major_step; + $grid[]=$xt; + $grid[]=$yt; + $aMajPos[($i-1)*2]=$xt+2*$dx; + $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2; + if( !$this->supress_tickmarks ) { + if( $this->majcolor != '' ) { + $aImg->PushColor($this->majcolor); + } + $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); + if( $this->majcolor != '' ) { + $aImg->PopColor(); + } + } + } + + // Draw minor ticks + $ticklen2=$this->minor_abs_size; + $dx=round(sin($aAxisAngle)*$ticklen2); + $dy=round(cos($aAxisAngle)*$ticklen2); + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor != '' ) { + $aImg->PushColor($this->mincolor); + } + for($i=1; $i<=$nbrmin; ++$i) { + if( ($i % $skip) == 0 ) { + continue; + } + $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($i*$min_step_abs*sin($aAxisAngle)); + $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); + } + if( $this->mincolor != '' ) { + $aImg->PopColor(); + } + } + } +} + + +//=================================================== +// CLASS RadarAxis +// Description: Implements axis for the radar graph +//=================================================== +class RadarAxis extends AxisPrototype { + public $title=null; + private $title_color='navy'; + private $len=0; + + function __construct($img,$aScale,$color=array(0,0,0)) { + parent::__construct($img,$aScale,$color); + $this->len = $img->plotheight; + $this->title = new Text(); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->color = array(0,0,0); + } + + // Stroke the axis + // $pos = Vertical position of axis + // $aAxisAngle = Axis angle + // $grid = Returns an array with positions used to draw the grid + // $lf = Label flag, TRUE if the axis should have labels + function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) { + $this->img->SetColor($this->color); + + // Determine end points for the axis + $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]); + $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle)); + + // Draw axis + $this->img->SetColor($this->color); + $this->img->SetLineWeight($this->weight); + if( !$this->hide ) { + $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y); + } + + $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel); + $ncolor=0; + if( isset($this->ticks_label_colors) ) { + $ncolor=count($this->ticks_label_colors); + } + + // Draw labels + if( $lf && !$this->hide ) { + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + $this->img->SetTextAlign('left','top'); + $this->img->SetColor($this->label_color); + + // majpos contains (x,y) coordinates for labels + if( ! $this->hide_labels ) { + $n = floor(count($majpos)/2); + for($i=0; $i < $n; ++$i) { + // Set specific label color if specified + if( $ncolor > 0 ) { + $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); + } + + if( $this->ticks_label != null && isset($this->ticks_label[$i]) ) { + $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]); + } + else { + $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]); + } + } + } + } + $this->_StrokeAxisTitle($pos,$aAxisAngle,$title); + } + + function _StrokeAxisTitle($pos,$aAxisAngle,$title) { + $this->title->Set($title); + $marg=6+$this->title->margin; + $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]); + $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle)); + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + if( $this->title->iWordwrap > 0 ) { + $title = wordwrap($title,$this->title->iWordwrap,"\n"); + } + + $h=$this->img->GetTextHeight($title)*1.2; + $w=$this->img->GetTextWidth($title)*1.2; + + while( $aAxisAngle > 2*M_PI ) + $aAxisAngle -= 2*M_PI; + + // Around 3 a'clock + if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=-0.15; // Small trimming to make the dist to the axis more even + + // Around 12 a'clock + if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; + + // Around 9 a'clock + if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1; + + // Around 6 a'clock + if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI); + + if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI; + if( $aAxisAngle<=M_PI/12 ) $dy=(0.5-$aAxisAngle*2/M_PI); + if( $aAxisAngle<=M_PI/4 && $aAxisAngle > M_PI/12) $dy=(1-$aAxisAngle*2/M_PI); + if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1; + if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI); + if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0; + + if( !$this->hide ) { + $this->title->Stroke($this->img,$xt-$dx*$w,$yt-$dy*$h,$title); + } + } + +} // Class + + +//=================================================== +// CLASS RadarGrid +// Description: Draws grid for the radar graph +//=================================================== +class RadarGrid { //extends Grid { + private $type='solid'; + private $grid_color='#DDDDDD'; + private $show=false, $weight=1; + + function __construct() { + // Empty + } + + function SetColor($aMajColor) { + $this->grid_color = $aMajColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + // Specify if grid should be dashed, dotted or solid + function SetLineStyle($aType) { + $this->type = $aType; + } + + // Decide if both major and minor grid should be displayed + function Show($aShowMajor=true) { + $this->show=$aShowMajor; + } + + function Stroke($img,$grid) { + if( !$this->show ) { + return; + } + + $nbrticks = count($grid[0])/2; + $nbrpnts = count($grid); + $img->SetColor($this->grid_color); + $img->SetLineWeight($this->weight); + + for($i=0; $i<$nbrticks; ++$i) { + for($j=0; $j<$nbrpnts; ++$j) { + $pnts[$j*2]=$grid[$j][$i*2]; + $pnts[$j*2+1]=$grid[$j][$i*2+1]; + } + for($k=0; $k<$nbrpnts; ++$k ){ + $l=($k+1)%$nbrpnts; + if( $this->type == 'solid' ) + $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]); + elseif( $this->type == 'dotted' ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6); + elseif( $this->type == 'dashed' ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4); + elseif( $this->type == 'longdashed' ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6); + } + $pnts=array(); + } + } +} // Class + + +//=================================================== +// CLASS RadarPlot +// Description: Plot a radarplot +//=================================================== +class RadarPlot { + public $mark=null; + public $legend=''; + public $legendcsimtarget=''; + public $legendcsimalt=''; + public $csimtargets=array(); // Array of targets for CSIM + public $csimareas=""; // Resultant CSIM area tags + public $csimalts=null; // ALT:s for corresponding target + private $data=array(); + private $fill=false, $fill_color=array(200,170,180); + private $color=array(0,0,0); + private $weight=1; + private $linestyle='solid'; + + //--------------- + // CONSTRUCTOR + function __construct($data) { + $this->data = $data; + $this->mark = new PlotMark(); + } + + function Min() { + return Min($this->data); + } + + function Max() { + return Max($this->data); + } + + function SetLegend($legend) { + $this->legend=$legend; + } + + function SetLineStyle($aStyle) { + $this->linestyle=$aStyle; + } + + function SetLineWeight($w) { + $this->weight=$w; + } + + function SetFillColor($aColor) { + $this->fill_color = $aColor; + $this->fill = true; + } + + function SetFill($f=true) { + $this->fill = $f; + } + + function SetColor($aColor,$aFillColor=false) { + $this->color = $aColor; + if( $aFillColor ) { + $this->SetFillColor($aFillColor); + $this->fill = true; + } + } + + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts=null) { + $this->csimtargets=$aTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + function Stroke($img, $pos, $scale, $startangle) { + $nbrpnts = count($this->data); + $astep=2*M_PI/$nbrpnts; + $a=$startangle; + + for($i=0; $i<$nbrpnts; ++$i) { + + // Rotate each non null point to the correct axis-angle + $cs=$scale->RelTranslate($this->data[$i]); + $x=round($cs*cos($a)+$scale->scale_abs[0]); + $y=round($pos-$cs*sin($a)); + + $pnts[$i*2]=$x; + $pnts[$i*2+1]=$y; + + // If the next point is null then we draw this polygon segment + // to the center, skip the next and draw the next segment from + // the center up to the point on the axis with the first non-null + // value and continues from that point. Some additoinal logic is necessary + // to handle the boundary conditions + if( $i < $nbrpnts-1 ) { + if( is_null($this->data[$i+1]) ) { + $cs = 0; + $x=round($cs*cos($a)+$scale->scale_abs[0]); + $y=round($pos-$cs*sin($a)); + $pnts[$i*2]=$x; + $pnts[$i*2+1]=$y; + $a += $astep; + } + } + + $a += $astep; + } + + if( $this->fill ) { + $img->SetColor($this->fill_color); + $img->FilledPolygon($pnts); + } + + $img->SetLineWeight($this->weight); + $img->SetColor($this->color); + $img->SetLineStyle($this->linestyle); + $pnts[] = $pnts[0]; + $pnts[] = $pnts[1]; + $img->Polygon($pnts); + $img->SetLineStyle('solid'); // Reset line style to default + + // Add plotmarks on top + if( $this->mark->show ) { + for($i=0; $i < $nbrpnts; ++$i) { + if( isset($this->csimtargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + $this->mark->SetCSIMAlt($this->csimalts[$i]); + $this->mark->SetCSIMAltVal($pnts[$i*2], $pnts[$i*2+1]); + $this->mark->Stroke($img, $pnts[$i*2], $pnts[$i*2+1]); + $this->csimareas .= $this->mark->GetCSIMAreas(); + } + else { + $this->mark->Stroke($img,$pnts[$i*2],$pnts[$i*2+1]); + } + } + } + + } + + function GetCount() { + return count($this->data); + } + + function Legend($graph) { + if( $this->legend == '' ) { + return; + } + if( $this->fill ) { + $graph->legend->Add($this->legend,$this->fill_color,$this->mark); + } else { + $graph->legend->Add($this->legend,$this->color,$this->mark); + } + } + +} // Class + +//=================================================== +// CLASS RadarGraph +// Description: Main container for a radar graph +//=================================================== +class RadarGraph extends Graph { + public $grid,$axis=null; + private $posx,$posy; + private $len; + private $axis_title=null; + + function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { + parent::__construct($width,$height,$cachedName,$timeout,$inline); + $this->posx = $width/2; + $this->posy = $height/2; + $this->len = min($width,$height)*0.35; + $this->SetColor(array(255,255,255)); + $this->SetTickDensity(TICKD_NORMAL); + $this->SetScale('lin'); + $this->SetGridDepth(DEPTH_FRONT); + } + + function HideTickMarks($aFlag=true) { + $this->axis->scale->ticks->SupressTickMarks($aFlag); + } + + function ShowMinorTickmarks($aFlag=true) { + $this->yscale->ticks->SupressMinorTickMarks(!$aFlag); + } + + function SetScale($axtype,$ymin=1,$ymax=1,$dummy1=null,$dumy2=null) { + if( $axtype != 'lin' && $axtype != 'log' ) { + JpGraphError::RaiseL(18003,$axtype); + //("Illegal scale for radarplot ($axtype). Must be \"lin\" or \"log\""); + } + if( $axtype == 'lin' ) { + $this->yscale = new LinearScale($ymin,$ymax); + $this->yscale->ticks = new RadarLinearTicks(); + $this->yscale->ticks->SupressMinorTickMarks(); + } + elseif( $axtype == 'log' ) { + $this->yscale = new LogScale($ymin,$ymax); + $this->yscale->ticks = new RadarLogTicks(); + } + + $this->axis = new RadarAxis($this->img,$this->yscale); + $this->grid = new RadarGrid(); + } + + function SetSize($aSize) { + if( $aSize < 0.1 || $aSize>1 ) { + JpGraphError::RaiseL(18004,$aSize); + //("Radar Plot size must be between 0.1 and 1. (Your value=$s)"); + } + $this->len=min($this->img->width,$this->img->height)*$aSize/2; + } + + function SetPlotSize($aSize) { + $this->SetSize($aSize); + } + + function SetTickDensity($densy=TICKD_NORMAL,$dummy1=null) { + $this->ytick_factor=25; + switch( $densy ) { + case TICKD_DENSE: + $this->ytick_factor=12; + break; + case TICKD_NORMAL: + $this->ytick_factor=25; + break; + case TICKD_SPARSE: + $this->ytick_factor=40; + break; + case TICKD_VERYSPARSE: + $this->ytick_factor=70; + break; + default: + JpGraphError::RaiseL(18005,$densy); + //("RadarPlot Unsupported Tick density: $densy"); + } + } + + function SetPos($px,$py=0.5) { + $this->SetCenter($px,$py); + } + + function SetCenter($px,$py=0.5) { + if( $px >= 0 && $px <= 1 ) { + $this->posx = $this->img->width*$px; + } + else { + $this->posx = $px; + } + if( $py >= 0 && $py <= 1 ) { + $this->posy = $this->img->height*$py; + } + else { + $this->posy = $py; + } + } + + function SetColor($aColor) { + $this->SetMarginColor($aColor); + } + + function SetTitles($aTitleArray) { + $this->axis_title = $aTitleArray; + } + + function Add($aPlot) { + if( $aPlot == null ) { + JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); + } + if( is_array($aPlot) && count($aPlot) > 0 ) { + $cl = $aPlot[0]; + } + else { + $cl = $aPlot; + } + + if( $cl instanceof Text ) $this->AddText($aPlot); + elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot); + else { + $this->plots[] = $aPlot; + } + } + + function GetPlotsYMinMax($aPlots) { + $min=$aPlots[0]->Min(); + $max=$aPlots[0]->Max(); + foreach( $this->plots as $p ) { + $max=max($max,$p->Max()); + $min=min($min,$p->Min()); + } + if( $min < 0 ) { + JpGraphError::RaiseL(18006,$min); + //("Minimum data $min (Radar plots should only be used when all data points > 0)"); + } + return array($min,$max); + } + + function StrokeIcons() { + if( $this->iIcons != null ) { + $n = count($this->iIcons); + for( $i=0; $i < $n; ++$i ) { + $this->iIcons[$i]->Stroke($this->img); + } + } + } + + function StrokeTexts() { + if( $this->texts != null ) { + $n = count($this->texts); + for( $i=0; $i < $n; ++$i ) { + $this->texts[$i]->Stroke($this->img); + } + } + } + + // Stroke the Radar graph + function Stroke($aStrokeFileName='') { + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ( $aStrokeFileName === _CSIM_SPECIALFILE ); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + $n = count($this->plots); + // Set Y-scale + + if( !$this->yscale->IsSpecified() && count($this->plots) > 0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->plots); + $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor); + } + elseif( $this->yscale->IsSpecified() && + ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { + + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->yscale->scale[0]; + $max = $this->yscale->scale[1]; + $this->yscale->AutoScale($this->img,$min,$max, + $this->len/$this->ytick_factor, + $this->yscale->auto_ticks); + } + + // Set start position end length of scale (in absolute pixels) + $this->yscale->SetConstants($this->posx,$this->len); + + // We need as many axis as there are data points + $nbrpnts=$this->plots[0]->GetCount(); + + // If we have no titles just number the axis 1,2,3,... + if( $this->axis_title==null ) { + for($i=0; $i < $nbrpnts; ++$i ) { + $this->axis_title[$i] = $i+1; + } + } + elseif( count($this->axis_title) < $nbrpnts) { + JpGraphError::RaiseL(18007); + // ("Number of titles does not match number of points in plot."); + } + for( $i=0; $i < $n; ++$i ) { + if( $nbrpnts != $this->plots[$i]->GetCount() ) { + JpGraphError::RaiseL(18008); + //("Each radar plot must have the same number of data points."); + } + } + + if( !$_csim ) { + if( $this->background_image != '' ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + $this->StrokeBackgroundGrad(); + } + } + $astep=2*M_PI/$nbrpnts; + + if( !$_csim ) { + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + + + // Prepare legends + for($i=0; $i < $n; ++$i) { + $this->plots[$i]->Legend($this); + } + $this->legend->Stroke($this->img); + $this->footer->Stroke($this->img); + } + + if( !$_csim ) { + if( $this->grid_depth == DEPTH_BACK ) { + // Draw axis and grid + for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { + $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); + } + $this->grid->Stroke($this->img,$grid); + } + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + + } + + // Plot points + $a=M_PI/2; + for($i=0; $i < $n; ++$i ) { + $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a); + } + + if( !$_csim ) { + if( $this->grid_depth != DEPTH_BACK ) { + // Draw axis and grid + for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { + $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); + } + $this->grid->Stroke($this->img,$grid); + } + + $this->StrokeTitles(); + $this->StrokeTexts(); + if( $this->iIconDepth == DEPTH_FRONT ) { + $this->StrokeIcons(); + } + } + + // Should we do any final image transformation + if( $this->iImgTrans && !$_csim ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + if( !$_csim ) { + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + } + } + } +} // Class + +/* EOF */ +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_regstat.php b/ext/jpgraph-3.0.7/src/jpgraph_regstat.php index cc0a99c..d21fbbc 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_regstat.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_regstat.php @@ -1,215 +1,215 @@ -y2 = array(); - $this->xdata = $xdata; - $this->ydata = $ydata; - - $n = count($ydata); - $this->n = $n; - if( $this->n !== count($xdata) ) { - JpGraphError::RaiseL(19001); - //('Spline: Number of X and Y coordinates must be the same'); - } - - // Natural spline 2:derivate == 0 at endpoints - $this->y2[0] = 0.0; - $this->y2[$n-1] = 0.0; - $delta[0] = 0.0; - - // Calculate 2:nd derivate - for($i=1; $i < $n-1; ++$i) { - $d = ($xdata[$i+1]-$xdata[$i-1]); - if( $d == 0 ) { - JpGraphError::RaiseL(19002); - //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); - } - $s = ($xdata[$i]-$xdata[$i-1])/$d; - $p = $s*$this->y2[$i-1]+2.0; - $this->y2[$i] = ($s-1.0)/$p; - $delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) - - ($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]); - $delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p; - } - - // Backward substitution - for( $j=$n-2; $j >= 0; --$j ) { - $this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j]; - } - } - - // Return the two new data vectors - function Get($num=50) { - $n = $this->n ; - $step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1); - $xnew=array(); - $ynew=array(); - $xnew[0] = $this->xdata[0]; - $ynew[0] = $this->ydata[0]; - for( $j=1; $j < $num; ++$j ) { - $xnew[$j] = $xnew[0]+$j*$step; - $ynew[$j] = $this->Interpolate($xnew[$j]); - } - return array($xnew,$ynew); - } - - // Return a single interpolated Y-value from an x value - function Interpolate($xpoint) { - - $max = $this->n-1; - $min = 0; - - // Binary search to find interval - while( $max-$min > 1 ) { - $k = ($max+$min) / 2; - if( $this->xdata[$k] > $xpoint ) - $max=$k; - else - $min=$k; - } - - // Each interval is interpolated by a 3:degree polynom function - $h = $this->xdata[$max]-$this->xdata[$min]; - - if( $h == 0 ) { - JpGraphError::RaiseL(19002); - //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); - } - - - $a = ($this->xdata[$max]-$xpoint)/$h; - $b = ($xpoint-$this->xdata[$min])/$h; - return $a*$this->ydata[$min]+$b*$this->ydata[$max]+ - (($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0; - } -} - -//------------------------------------------------------------------------ -// CLASS Bezier -// Create a new data array from a number of control points -//------------------------------------------------------------------------ -class Bezier { - /** - * @author Thomas Despoix, openXtrem company - * @license released under QPL - * @abstract Bezier interoplated point generation, - * computed from control points data sets, based on Paul Bourke algorithm : - * http://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.html - */ - private $datax = array(); - private $datay = array(); - private $n=0; - - function __construct($datax, $datay, $attraction_factor = 1) { - // Adding control point multiple time will raise their attraction power over the curve - $this->n = count($datax); - if( $this->n !== count($datay) ) { - JpGraphError::RaiseL(19003); - //('Bezier: Number of X and Y coordinates must be the same'); - } - $idx=0; - foreach($datax as $datumx) { - for ($i = 0; $i < $attraction_factor; $i++) { - $this->datax[$idx++] = $datumx; - } - } - $idx=0; - foreach($datay as $datumy) { - for ($i = 0; $i < $attraction_factor; $i++) { - $this->datay[$idx++] = $datumy; - } - } - $this->n *= $attraction_factor; - } - - /** - * Return a set of data points that specifies the bezier curve with $steps points - * @param $steps Number of new points to return - * @return array($datax, $datay) - */ - function Get($steps) { - $datax = array(); - $datay = array(); - for ($i = 0; $i < $steps; $i++) { - list($datumx, $datumy) = $this->GetPoint((double) $i / (double) $steps); - $datax[$i] = $datumx; - $datay[$i] = $datumy; - } - - $datax[] = end($this->datax); - $datay[] = end($this->datay); - - return array($datax, $datay); - } - - /** - * Return one point on the bezier curve. $mu is the position on the curve where $mu is in the - * range 0 $mu < 1 where 0 is tha start point and 1 is the end point. Note that every newly computed - * point depends on all the existing points - * - * @param $mu Position on the bezier curve - * @return array($x, $y) - */ - function GetPoint($mu) { - $n = $this->n - 1; - $k = 0; - $kn = 0; - $nn = 0; - $nkn = 0; - $blend = 0.0; - $newx = 0.0; - $newy = 0.0; - - $muk = 1.0; - $munk = (double) pow(1-$mu,(double) $n); - - for ($k = 0; $k <= $n; $k++) { - $nn = $n; - $kn = $k; - $nkn = $n - $k; - $blend = $muk * $munk; - $muk *= $mu; - $munk /= (1-$mu); - while ($nn >= 1) { - $blend *= $nn; - $nn--; - if ($kn > 1) { - $blend /= (double) $kn; - $kn--; - } - if ($nkn > 1) { - $blend /= (double) $nkn; - $nkn--; - } - } - $newx += $this->datax[$k] * $blend; - $newy += $this->datay[$k] * $blend; - } - - return array($newx, $newy); - } -} - -// EOF -?> +y2 = array(); + $this->xdata = $xdata; + $this->ydata = $ydata; + + $n = count($ydata); + $this->n = $n; + if( $this->n !== count($xdata) ) { + JpGraphError::RaiseL(19001); + //('Spline: Number of X and Y coordinates must be the same'); + } + + // Natural spline 2:derivate == 0 at endpoints + $this->y2[0] = 0.0; + $this->y2[$n-1] = 0.0; + $delta[0] = 0.0; + + // Calculate 2:nd derivate + for($i=1; $i < $n-1; ++$i) { + $d = ($xdata[$i+1]-$xdata[$i-1]); + if( $d == 0 ) { + JpGraphError::RaiseL(19002); + //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); + } + $s = ($xdata[$i]-$xdata[$i-1])/$d; + $p = $s*$this->y2[$i-1]+2.0; + $this->y2[$i] = ($s-1.0)/$p; + $delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) - + ($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]); + $delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p; + } + + // Backward substitution + for( $j=$n-2; $j >= 0; --$j ) { + $this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j]; + } + } + + // Return the two new data vectors + function Get($num=50) { + $n = $this->n ; + $step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1); + $xnew=array(); + $ynew=array(); + $xnew[0] = $this->xdata[0]; + $ynew[0] = $this->ydata[0]; + for( $j=1; $j < $num; ++$j ) { + $xnew[$j] = $xnew[0]+$j*$step; + $ynew[$j] = $this->Interpolate($xnew[$j]); + } + return array($xnew,$ynew); + } + + // Return a single interpolated Y-value from an x value + function Interpolate($xpoint) { + + $max = $this->n-1; + $min = 0; + + // Binary search to find interval + while( $max-$min > 1 ) { + $k = ($max+$min) / 2; + if( $this->xdata[$k] > $xpoint ) + $max=$k; + else + $min=$k; + } + + // Each interval is interpolated by a 3:degree polynom function + $h = $this->xdata[$max]-$this->xdata[$min]; + + if( $h == 0 ) { + JpGraphError::RaiseL(19002); + //('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); + } + + + $a = ($this->xdata[$max]-$xpoint)/$h; + $b = ($xpoint-$this->xdata[$min])/$h; + return $a*$this->ydata[$min]+$b*$this->ydata[$max]+ + (($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0; + } +} + +//------------------------------------------------------------------------ +// CLASS Bezier +// Create a new data array from a number of control points +//------------------------------------------------------------------------ +class Bezier { + /** + * @author Thomas Despoix, openXtrem company + * @license released under QPL + * @abstract Bezier interoplated point generation, + * computed from control points data sets, based on Paul Bourke algorithm : + * http://local.wasp.uwa.edu.au/~pbourke/geometry/bezier/index2.html + */ + private $datax = array(); + private $datay = array(); + private $n=0; + + function __construct($datax, $datay, $attraction_factor = 1) { + // Adding control point multiple time will raise their attraction power over the curve + $this->n = count($datax); + if( $this->n !== count($datay) ) { + JpGraphError::RaiseL(19003); + //('Bezier: Number of X and Y coordinates must be the same'); + } + $idx=0; + foreach($datax as $datumx) { + for ($i = 0; $i < $attraction_factor; $i++) { + $this->datax[$idx++] = $datumx; + } + } + $idx=0; + foreach($datay as $datumy) { + for ($i = 0; $i < $attraction_factor; $i++) { + $this->datay[$idx++] = $datumy; + } + } + $this->n *= $attraction_factor; + } + + /** + * Return a set of data points that specifies the bezier curve with $steps points + * @param $steps Number of new points to return + * @return array($datax, $datay) + */ + function Get($steps) { + $datax = array(); + $datay = array(); + for ($i = 0; $i < $steps; $i++) { + list($datumx, $datumy) = $this->GetPoint((double) $i / (double) $steps); + $datax[$i] = $datumx; + $datay[$i] = $datumy; + } + + $datax[] = end($this->datax); + $datay[] = end($this->datay); + + return array($datax, $datay); + } + + /** + * Return one point on the bezier curve. $mu is the position on the curve where $mu is in the + * range 0 $mu < 1 where 0 is tha start point and 1 is the end point. Note that every newly computed + * point depends on all the existing points + * + * @param $mu Position on the bezier curve + * @return array($x, $y) + */ + function GetPoint($mu) { + $n = $this->n - 1; + $k = 0; + $kn = 0; + $nn = 0; + $nkn = 0; + $blend = 0.0; + $newx = 0.0; + $newy = 0.0; + + $muk = 1.0; + $munk = (double) pow(1-$mu,(double) $n); + + for ($k = 0; $k <= $n; $k++) { + $nn = $n; + $kn = $k; + $nkn = $n - $k; + $blend = $muk * $munk; + $muk *= $mu; + $munk /= (1-$mu); + while ($nn >= 1) { + $blend *= $nn; + $nn--; + if ($kn > 1) { + $blend /= (double) $kn; + $kn--; + } + if ($nkn > 1) { + $blend /= (double) $nkn; + $nkn--; + } + } + $newx += $this->datax[$k] * $blend; + $newy += $this->datay[$k] * $blend; + } + + return array($newx, $newy); + } +} + +// EOF +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_rgb.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_rgb.inc.php index 2cbc85b..8e70d9a 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_rgb.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_rgb.inc.php @@ -1,615 +1,615 @@ -img = $aImg; - - // Conversion array between color names and RGB - $this->rgb_table = array( - 'aqua'=> array(0,255,255), - 'lime'=> array(0,255,0), - 'teal'=> array(0,128,128), - 'whitesmoke'=>array(245,245,245), - 'gainsboro'=>array(220,220,220), - 'oldlace'=>array(253,245,230), - 'linen'=>array(250,240,230), - 'antiquewhite'=>array(250,235,215), - 'papayawhip'=>array(255,239,213), - 'blanchedalmond'=>array(255,235,205), - 'bisque'=>array(255,228,196), - 'peachpuff'=>array(255,218,185), - 'navajowhite'=>array(255,222,173), - 'moccasin'=>array(255,228,181), - 'cornsilk'=>array(255,248,220), - 'ivory'=>array(255,255,240), - 'lemonchiffon'=>array(255,250,205), - 'seashell'=>array(255,245,238), - 'mintcream'=>array(245,255,250), - 'azure'=>array(240,255,255), - 'aliceblue'=>array(240,248,255), - 'lavender'=>array(230,230,250), - 'lavenderblush'=>array(255,240,245), - 'mistyrose'=>array(255,228,225), - 'white'=>array(255,255,255), - 'black'=>array(0,0,0), - 'darkslategray'=>array(47,79,79), - 'dimgray'=>array(105,105,105), - 'slategray'=>array(112,128,144), - 'lightslategray'=>array(119,136,153), - 'gray'=>array(190,190,190), - 'lightgray'=>array(211,211,211), - 'midnightblue'=>array(25,25,112), - 'navy'=>array(0,0,128), - 'indigo'=>array(75,0,130), - 'electricindigo'=>array(102,0,255), - 'deepindigo'=>array(138,43,226), - 'pigmentindigo'=>array(75,0,130), - 'indigodye'=>array(0,65,106), - 'cornflowerblue'=>array(100,149,237), - 'darkslateblue'=>array(72,61,139), - 'slateblue'=>array(106,90,205), - 'mediumslateblue'=>array(123,104,238), - 'lightslateblue'=>array(132,112,255), - 'mediumblue'=>array(0,0,205), - 'royalblue'=>array(65,105,225), - 'blue'=>array(0,0,255), - 'dodgerblue'=>array(30,144,255), - 'deepskyblue'=>array(0,191,255), - 'skyblue'=>array(135,206,235), - 'lightskyblue'=>array(135,206,250), - 'steelblue'=>array(70,130,180), - 'lightred'=>array(211,167,168), - 'lightsteelblue'=>array(176,196,222), - 'lightblue'=>array(173,216,230), - 'powderblue'=>array(176,224,230), - 'paleturquoise'=>array(175,238,238), - 'darkturquoise'=>array(0,206,209), - 'mediumturquoise'=>array(72,209,204), - 'turquoise'=>array(64,224,208), - 'cyan'=>array(0,255,255), - 'lightcyan'=>array(224,255,255), - 'cadetblue'=>array(95,158,160), - 'mediumaquamarine'=>array(102,205,170), - 'aquamarine'=>array(127,255,212), - 'darkgreen'=>array(0,100,0), - 'darkolivegreen'=>array(85,107,47), - 'darkseagreen'=>array(143,188,143), - 'seagreen'=>array(46,139,87), - 'mediumseagreen'=>array(60,179,113), - 'lightseagreen'=>array(32,178,170), - 'palegreen'=>array(152,251,152), - 'springgreen'=>array(0,255,127), - 'lawngreen'=>array(124,252,0), - 'green'=>array(0,255,0), - 'chartreuse'=>array(127,255,0), - 'mediumspringgreen'=>array(0,250,154), - 'greenyellow'=>array(173,255,47), - 'limegreen'=>array(50,205,50), - 'yellowgreen'=>array(154,205,50), - 'forestgreen'=>array(34,139,34), - 'olivedrab'=>array(107,142,35), - 'darkkhaki'=>array(189,183,107), - 'khaki'=>array(240,230,140), - 'palegoldenrod'=>array(238,232,170), - 'lightgoldenrodyellow'=>array(250,250,210), - 'lightyellow'=>array(255,255,200), - 'yellow'=>array(255,255,0), - 'gold'=>array(255,215,0), - 'lightgoldenrod'=>array(238,221,130), - 'goldenrod'=>array(218,165,32), - 'darkgoldenrod'=>array(184,134,11), - 'rosybrown'=>array(188,143,143), - 'indianred'=>array(205,92,92), - 'saddlebrown'=>array(139,69,19), - 'sienna'=>array(160,82,45), - 'peru'=>array(205,133,63), - 'burlywood'=>array(222,184,135), - 'beige'=>array(245,245,220), - 'wheat'=>array(245,222,179), - 'sandybrown'=>array(244,164,96), - 'tan'=>array(210,180,140), - 'chocolate'=>array(210,105,30), - 'firebrick'=>array(178,34,34), - 'brown'=>array(165,42,42), - 'darksalmon'=>array(233,150,122), - 'salmon'=>array(250,128,114), - 'lightsalmon'=>array(255,160,122), - 'orange'=>array(255,165,0), - 'darkorange'=>array(255,140,0), - 'coral'=>array(255,127,80), - 'lightcoral'=>array(240,128,128), - 'tomato'=>array(255,99,71), - 'orangered'=>array(255,69,0), - 'red'=>array(255,0,0), - 'hotpink'=>array(255,105,180), - 'deeppink'=>array(255,20,147), - 'pink'=>array(255,192,203), - 'lightpink'=>array(255,182,193), - 'palevioletred'=>array(219,112,147), - 'maroon'=>array(176,48,96), - 'mediumvioletred'=>array(199,21,133), - 'violetred'=>array(208,32,144), - 'magenta'=>array(255,0,255), - 'violet'=>array(238,130,238), - 'plum'=>array(221,160,221), - 'orchid'=>array(218,112,214), - 'mediumorchid'=>array(186,85,211), - 'darkorchid'=>array(153,50,204), - 'darkviolet'=>array(148,0,211), - 'blueviolet'=>array(138,43,226), - 'purple'=>array(160,32,240), - 'mediumpurple'=>array(147,112,219), - 'thistle'=>array(216,191,216), - 'snow1'=>array(255,250,250), - 'snow2'=>array(238,233,233), - 'snow3'=>array(205,201,201), - 'snow4'=>array(139,137,137), - 'seashell1'=>array(255,245,238), - 'seashell2'=>array(238,229,222), - 'seashell3'=>array(205,197,191), - 'seashell4'=>array(139,134,130), - 'AntiqueWhite1'=>array(255,239,219), - 'AntiqueWhite2'=>array(238,223,204), - 'AntiqueWhite3'=>array(205,192,176), - 'AntiqueWhite4'=>array(139,131,120), - 'bisque1'=>array(255,228,196), - 'bisque2'=>array(238,213,183), - 'bisque3'=>array(205,183,158), - 'bisque4'=>array(139,125,107), - 'peachPuff1'=>array(255,218,185), - 'peachpuff2'=>array(238,203,173), - 'peachpuff3'=>array(205,175,149), - 'peachpuff4'=>array(139,119,101), - 'navajowhite1'=>array(255,222,173), - 'navajowhite2'=>array(238,207,161), - 'navajowhite3'=>array(205,179,139), - 'navajowhite4'=>array(139,121,94), - 'lemonchiffon1'=>array(255,250,205), - 'lemonchiffon2'=>array(238,233,191), - 'lemonchiffon3'=>array(205,201,165), - 'lemonchiffon4'=>array(139,137,112), - 'ivory1'=>array(255,255,240), - 'ivory2'=>array(238,238,224), - 'ivory3'=>array(205,205,193), - 'ivory4'=>array(139,139,131), - 'honeydew'=>array(193,205,193), - 'lavenderblush1'=>array(255,240,245), - 'lavenderblush2'=>array(238,224,229), - 'lavenderblush3'=>array(205,193,197), - 'lavenderblush4'=>array(139,131,134), - 'mistyrose1'=>array(255,228,225), - 'mistyrose2'=>array(238,213,210), - 'mistyrose3'=>array(205,183,181), - 'mistyrose4'=>array(139,125,123), - 'azure1'=>array(240,255,255), - 'azure2'=>array(224,238,238), - 'azure3'=>array(193,205,205), - 'azure4'=>array(131,139,139), - 'slateblue1'=>array(131,111,255), - 'slateblue2'=>array(122,103,238), - 'slateblue3'=>array(105,89,205), - 'slateblue4'=>array(71,60,139), - 'royalblue1'=>array(72,118,255), - 'royalblue2'=>array(67,110,238), - 'royalblue3'=>array(58,95,205), - 'royalblue4'=>array(39,64,139), - 'dodgerblue1'=>array(30,144,255), - 'dodgerblue2'=>array(28,134,238), - 'dodgerblue3'=>array(24,116,205), - 'dodgerblue4'=>array(16,78,139), - 'steelblue1'=>array(99,184,255), - 'steelblue2'=>array(92,172,238), - 'steelblue3'=>array(79,148,205), - 'steelblue4'=>array(54,100,139), - 'deepskyblue1'=>array(0,191,255), - 'deepskyblue2'=>array(0,178,238), - 'deepskyblue3'=>array(0,154,205), - 'deepskyblue4'=>array(0,104,139), - 'skyblue1'=>array(135,206,255), - 'skyblue2'=>array(126,192,238), - 'skyblue3'=>array(108,166,205), - 'skyblue4'=>array(74,112,139), - 'lightskyblue1'=>array(176,226,255), - 'lightskyblue2'=>array(164,211,238), - 'lightskyblue3'=>array(141,182,205), - 'lightskyblue4'=>array(96,123,139), - 'slategray1'=>array(198,226,255), - 'slategray2'=>array(185,211,238), - 'slategray3'=>array(159,182,205), - 'slategray4'=>array(108,123,139), - 'lightsteelblue1'=>array(202,225,255), - 'lightsteelblue2'=>array(188,210,238), - 'lightsteelblue3'=>array(162,181,205), - 'lightsteelblue4'=>array(110,123,139), - 'lightblue1'=>array(191,239,255), - 'lightblue2'=>array(178,223,238), - 'lightblue3'=>array(154,192,205), - 'lightblue4'=>array(104,131,139), - 'lightcyan1'=>array(224,255,255), - 'lightcyan2'=>array(209,238,238), - 'lightcyan3'=>array(180,205,205), - 'lightcyan4'=>array(122,139,139), - 'paleturquoise1'=>array(187,255,255), - 'paleturquoise2'=>array(174,238,238), - 'paleturquoise3'=>array(150,205,205), - 'paleturquoise4'=>array(102,139,139), - 'cadetblue1'=>array(152,245,255), - 'cadetblue2'=>array(142,229,238), - 'cadetblue3'=>array(122,197,205), - 'cadetblue4'=>array(83,134,139), - 'turquoise1'=>array(0,245,255), - 'turquoise2'=>array(0,229,238), - 'turquoise3'=>array(0,197,205), - 'turquoise4'=>array(0,134,139), - 'cyan1'=>array(0,255,255), - 'cyan2'=>array(0,238,238), - 'cyan3'=>array(0,205,205), - 'cyan4'=>array(0,139,139), - 'darkslategray1'=>array(151,255,255), - 'darkslategray2'=>array(141,238,238), - 'darkslategray3'=>array(121,205,205), - 'darkslategray4'=>array(82,139,139), - 'aquamarine1'=>array(127,255,212), - 'aquamarine2'=>array(118,238,198), - 'aquamarine3'=>array(102,205,170), - 'aquamarine4'=>array(69,139,116), - 'darkseagreen1'=>array(193,255,193), - 'darkseagreen2'=>array(180,238,180), - 'darkseagreen3'=>array(155,205,155), - 'darkseagreen4'=>array(105,139,105), - 'seagreen1'=>array(84,255,159), - 'seagreen2'=>array(78,238,148), - 'seagreen3'=>array(67,205,128), - 'seagreen4'=>array(46,139,87), - 'palegreen1'=>array(154,255,154), - 'palegreen2'=>array(144,238,144), - 'palegreen3'=>array(124,205,124), - 'palegreen4'=>array(84,139,84), - 'springgreen1'=>array(0,255,127), - 'springgreen2'=>array(0,238,118), - 'springgreen3'=>array(0,205,102), - 'springgreen4'=>array(0,139,69), - 'chartreuse1'=>array(127,255,0), - 'chartreuse2'=>array(118,238,0), - 'chartreuse3'=>array(102,205,0), - 'chartreuse4'=>array(69,139,0), - 'olivedrab1'=>array(192,255,62), - 'olivedrab2'=>array(179,238,58), - 'olivedrab3'=>array(154,205,50), - 'olivedrab4'=>array(105,139,34), - 'darkolivegreen1'=>array(202,255,112), - 'darkolivegreen2'=>array(188,238,104), - 'darkolivegreen3'=>array(162,205,90), - 'darkolivegreen4'=>array(110,139,61), - 'khaki1'=>array(255,246,143), - 'khaki2'=>array(238,230,133), - 'khaki3'=>array(205,198,115), - 'khaki4'=>array(139,134,78), - 'lightgoldenrod1'=>array(255,236,139), - 'lightgoldenrod2'=>array(238,220,130), - 'lightgoldenrod3'=>array(205,190,112), - 'lightgoldenrod4'=>array(139,129,76), - 'yellow1'=>array(255,255,0), - 'yellow2'=>array(238,238,0), - 'yellow3'=>array(205,205,0), - 'yellow4'=>array(139,139,0), - 'gold1'=>array(255,215,0), - 'gold2'=>array(238,201,0), - 'gold3'=>array(205,173,0), - 'gold4'=>array(139,117,0), - 'goldenrod1'=>array(255,193,37), - 'goldenrod2'=>array(238,180,34), - 'goldenrod3'=>array(205,155,29), - 'goldenrod4'=>array(139,105,20), - 'darkgoldenrod1'=>array(255,185,15), - 'darkgoldenrod2'=>array(238,173,14), - 'darkgoldenrod3'=>array(205,149,12), - 'darkgoldenrod4'=>array(139,101,8), - 'rosybrown1'=>array(255,193,193), - 'rosybrown2'=>array(238,180,180), - 'rosybrown3'=>array(205,155,155), - 'rosybrown4'=>array(139,105,105), - 'indianred1'=>array(255,106,106), - 'indianred2'=>array(238,99,99), - 'indianred3'=>array(205,85,85), - 'indianred4'=>array(139,58,58), - 'sienna1'=>array(255,130,71), - 'sienna2'=>array(238,121,66), - 'sienna3'=>array(205,104,57), - 'sienna4'=>array(139,71,38), - 'burlywood1'=>array(255,211,155), - 'burlywood2'=>array(238,197,145), - 'burlywood3'=>array(205,170,125), - 'burlywood4'=>array(139,115,85), - 'wheat1'=>array(255,231,186), - 'wheat2'=>array(238,216,174), - 'wheat3'=>array(205,186,150), - 'wheat4'=>array(139,126,102), - 'tan1'=>array(255,165,79), - 'tan2'=>array(238,154,73), - 'tan3'=>array(205,133,63), - 'tan4'=>array(139,90,43), - 'chocolate1'=>array(255,127,36), - 'chocolate2'=>array(238,118,33), - 'chocolate3'=>array(205,102,29), - 'chocolate4'=>array(139,69,19), - 'firebrick1'=>array(255,48,48), - 'firebrick2'=>array(238,44,44), - 'firebrick3'=>array(205,38,38), - 'firebrick4'=>array(139,26,26), - 'brown1'=>array(255,64,64), - 'brown2'=>array(238,59,59), - 'brown3'=>array(205,51,51), - 'brown4'=>array(139,35,35), - 'salmon1'=>array(255,140,105), - 'salmon2'=>array(238,130,98), - 'salmon3'=>array(205,112,84), - 'salmon4'=>array(139,76,57), - 'lightsalmon1'=>array(255,160,122), - 'lightsalmon2'=>array(238,149,114), - 'lightsalmon3'=>array(205,129,98), - 'lightsalmon4'=>array(139,87,66), - 'orange1'=>array(255,165,0), - 'orange2'=>array(238,154,0), - 'orange3'=>array(205,133,0), - 'orange4'=>array(139,90,0), - 'darkorange1'=>array(255,127,0), - 'darkorange2'=>array(238,118,0), - 'darkorange3'=>array(205,102,0), - 'darkorange4'=>array(139,69,0), - 'coral1'=>array(255,114,86), - 'coral2'=>array(238,106,80), - 'coral3'=>array(205,91,69), - 'coral4'=>array(139,62,47), - 'tomato1'=>array(255,99,71), - 'tomato2'=>array(238,92,66), - 'tomato3'=>array(205,79,57), - 'tomato4'=>array(139,54,38), - 'orangered1'=>array(255,69,0), - 'orangered2'=>array(238,64,0), - 'orangered3'=>array(205,55,0), - 'orangered4'=>array(139,37,0), - 'deeppink1'=>array(255,20,147), - 'deeppink2'=>array(238,18,137), - 'deeppink3'=>array(205,16,118), - 'deeppink4'=>array(139,10,80), - 'hotpink1'=>array(255,110,180), - 'hotpink2'=>array(238,106,167), - 'hotpink3'=>array(205,96,144), - 'hotpink4'=>array(139,58,98), - 'pink1'=>array(255,181,197), - 'pink2'=>array(238,169,184), - 'pink3'=>array(205,145,158), - 'pink4'=>array(139,99,108), - 'lightpink1'=>array(255,174,185), - 'lightpink2'=>array(238,162,173), - 'lightpink3'=>array(205,140,149), - 'lightpink4'=>array(139,95,101), - 'palevioletred1'=>array(255,130,171), - 'palevioletred2'=>array(238,121,159), - 'palevioletred3'=>array(205,104,137), - 'palevioletred4'=>array(139,71,93), - 'maroon1'=>array(255,52,179), - 'maroon2'=>array(238,48,167), - 'maroon3'=>array(205,41,144), - 'maroon4'=>array(139,28,98), - 'violetred1'=>array(255,62,150), - 'violetred2'=>array(238,58,140), - 'violetred3'=>array(205,50,120), - 'violetred4'=>array(139,34,82), - 'magenta1'=>array(255,0,255), - 'magenta2'=>array(238,0,238), - 'magenta3'=>array(205,0,205), - 'magenta4'=>array(139,0,139), - 'mediumred'=>array(140,34,34), - 'orchid1'=>array(255,131,250), - 'orchid2'=>array(238,122,233), - 'orchid3'=>array(205,105,201), - 'orchid4'=>array(139,71,137), - 'plum1'=>array(255,187,255), - 'plum2'=>array(238,174,238), - 'plum3'=>array(205,150,205), - 'plum4'=>array(139,102,139), - 'mediumorchid1'=>array(224,102,255), - 'mediumorchid2'=>array(209,95,238), - 'mediumorchid3'=>array(180,82,205), - 'mediumorchid4'=>array(122,55,139), - 'darkorchid1'=>array(191,62,255), - 'darkorchid2'=>array(178,58,238), - 'darkorchid3'=>array(154,50,205), - 'darkorchid4'=>array(104,34,139), - 'purple1'=>array(155,48,255), - 'purple2'=>array(145,44,238), - 'purple3'=>array(125,38,205), - 'purple4'=>array(85,26,139), - 'mediumpurple1'=>array(171,130,255), - 'mediumpurple2'=>array(159,121,238), - 'mediumpurple3'=>array(137,104,205), - 'mediumpurple4'=>array(93,71,139), - 'thistle1'=>array(255,225,255), - 'thistle2'=>array(238,210,238), - 'thistle3'=>array(205,181,205), - 'thistle4'=>array(139,123,139), - 'gray1'=>array(10,10,10), - 'gray2'=>array(40,40,30), - 'gray3'=>array(70,70,70), - 'gray4'=>array(100,100,100), - 'gray5'=>array(130,130,130), - 'gray6'=>array(160,160,160), - 'gray7'=>array(190,190,190), - 'gray8'=>array(210,210,210), - 'gray9'=>array(240,240,240), - 'darkgray'=>array(100,100,100), - 'darkblue'=>array(0,0,139), - 'darkcyan'=>array(0,139,139), - 'darkmagenta'=>array(139,0,139), - 'darkred'=>array(139,0,0), - 'silver'=>array(192, 192, 192), - 'eggplant'=>array(144,176,168), - 'lightgreen'=>array(144,238,144)); - } - - - //---------------- - // PUBLIC METHODS - // Colors can be specified as either - // 1. #xxxxxx HTML style - // 2. "colorname" as a named color - // 3. array(r,g,b) RGB triple - // This function translates this to a native RGB format and returns an - // RGB triple. - - function Color($aColor) { - if (is_string($aColor)) { - $matches = array(); - // this regex will parse a color string and fill the $matches array as such: - // 0: the full match if any - // 1: a hex string preceded by a hash, can be 3 characters (#fff) or 6 (#ffffff) (4 or 5 also accepted but...) - // 2,3,4: r,g,b values in hex if the first character of the string is # - // 5: all alpha-numeric characters at the beginning of the string if string does not start with # - // 6: alpha value prefixed by @ if supplied - // 7: alpha value with @ stripped - // 8: adjust value prefixed with : if supplied - // 9: adjust value with : stripped - $regex = '/(#([0-9a-fA-F]{1,2})([0-9a-fA-F]{1,2})([0-9a-fA-F]{1,2}))?([\w]+)?(@([\d\.,]+))?(:([\d\.,]+))?/'; - if(!preg_match($regex, $aColor, $matches)) { - JpGraphError::RaiseL(25078,$aColor);//(" Unknown color: $aColor"); - } - if(empty($matches[5])) { - $r = strlen($matches[2]) == 1 ? $matches[2].$matches[2] : $matches[2]; - $g = strlen($matches[3]) == 1 ? $matches[3].$matches[3] : $matches[3]; - $b = strlen($matches[4]) == 1 ? $matches[4].$matches[4] : $matches[4]; - $r = hexdec($r); - $g = hexdec($g); - $b = hexdec($b); - }else { - if(!isset($this->rgb_table[$matches[5]]) ) { - JpGraphError::RaiseL(25078,$aColor);//(" Unknown color: $aColor"); - } - $r = $this->rgb_table[$matches[5]][0]; - $g = $this->rgb_table[$matches[5]][1]; - $b = $this->rgb_table[$matches[5]][2]; - } - $alpha = isset($matches[7]) ? str_replace(',','.',$matches[7]) : 0; - $adj = isset($matches[9]) ? str_replace(',','.',$matches[9]) : 1.0; - - if( $adj < 0 ) { - JpGraphError::RaiseL(25077);//('Adjustment factor for color must be > 0'); - } - - // Scale adj so that an adj=2 always - // makes the color 100% white (i.e. 255,255,255. - // and adj=1 neutral and adj=0 black. - if( $adj == 1) { - return array($r,$g,$b,$alpha); - } - elseif( $adj > 1 ) { - $m = ($adj-1.0)*(255-min(255,min($r,min($g,$b)))); - return array(min(255,$r+$m), min(255,$g+$m), min(255,$b+$m),$alpha); - } - elseif( $adj < 1 ) { - $m = ($adj-1.0)*max(255,max($r,max($g,$b))); - return array(max(0,$r+$m), max(0,$g+$m), max(0,$b+$m),$alpha); - } - } elseif( is_array($aColor) ) { - if(!isset($aColor[3])) $aColor[3] = 0; - return $aColor; - } - else { - JpGraphError::RaiseL(25079,$aColor,count($aColor));//(" Unknown color specification: $aColor , size=".count($aColor)); - } - } - - // Compare two colors - // return true if equal - function Equal($aCol1,$aCol2) { - $c1 = $this->Color($aCol1); - $c2 = $this->Color($aCol2); - return $c1[0]==$c2[0] && $c1[1]==$c2[1] && $c1[2]==$c2[2] ; - } - - // Allocate a new color in the current image - // Return new color index, -1 if no more colors could be allocated - function Allocate($aColor,$aAlpha=0.0) { - list ($r, $g, $b, $a) = $this->color($aColor); - // If alpha is specified in the color string then this - // takes precedence over the second argument - if( $a > 0 ) { - $aAlpha = $a; - } - if( $aAlpha < 0 || $aAlpha > 1 ) { - JpGraphError::RaiseL(25080);//('Alpha parameter for color must be between 0.0 and 1.0'); - } - return imagecolorresolvealpha($this->img, $r, $g, $b, round($aAlpha * 127)); - } - - // Try to convert an array with three valid numbers to the corresponding hex array - // This is currenly only used in processing the colors for barplots in order to be able - // to handle the case where the color might be specified as an array of colros as well. - // In that case we must be able to find out if an array of values should be interpretated as - // a single color (specifeid as an RGB triple) - static function tryHexConversion($aColor) { - if( is_array( $aColor ) ) { - if( count( $aColor ) == 3 ) { - if( is_numeric($aColor[0]) && is_numeric($aColor[1]) && is_numeric($aColor[2]) ) { - if( ($aColor[0] >= 0 && $aColor[0] <= 255) && - ($aColor[1] >= 0 && $aColor[1] <= 255) && - ($aColor[2] >= 0 && $aColor[2] <= 255) ) { - return sprintf('#%02x%02x%02x',$aColor[0],$aColor[1],$aColor[2]); - } - } - } - } - return $aColor; - } - - // Return a RGB tripple corresponding to a position in the normal light spectrum - // The argumen values is in the range [0, 1] where a value of 0 correponds to blue and - // a value of 1 corresponds to red. Values in betwen is mapped to a linear interpolation - // of the constituting colors in the visible color spectra. - // The $aDynamicRange specified how much of the dynamic range we shold use - // a value of 1.0 give the full dyanmic range and a lower value give more dark - // colors. In the extreme of 0.0 then all colors will be black. - static function GetSpectrum($aVal,$aDynamicRange=1.0) { - if( $aVal < 0 || $aVal > 1.0001 ) { - return array(0,0,0); // Invalid case - just return black - } - - $sat = round(255*$aDynamicRange); - $a = 0.25; - if( $aVal <= 0.25 ) { - return array(0, round($sat*$aVal/$a), $sat); - } - elseif( $aVal <= 0.5 ) { - return array(0, $sat, round($sat-$sat*($aVal-0.25)/$a)); - } - elseif( $aVal <= 0.75 ) { - return array(round($sat*($aVal-0.5)/$a), $sat, 0); - } - else { - return array($sat, round($sat-$sat*($aVal-0.75)/$a), 0); - } - } - -} // Class - -?> +img = $aImg; + + // Conversion array between color names and RGB + $this->rgb_table = array( + 'aqua'=> array(0,255,255), + 'lime'=> array(0,255,0), + 'teal'=> array(0,128,128), + 'whitesmoke'=>array(245,245,245), + 'gainsboro'=>array(220,220,220), + 'oldlace'=>array(253,245,230), + 'linen'=>array(250,240,230), + 'antiquewhite'=>array(250,235,215), + 'papayawhip'=>array(255,239,213), + 'blanchedalmond'=>array(255,235,205), + 'bisque'=>array(255,228,196), + 'peachpuff'=>array(255,218,185), + 'navajowhite'=>array(255,222,173), + 'moccasin'=>array(255,228,181), + 'cornsilk'=>array(255,248,220), + 'ivory'=>array(255,255,240), + 'lemonchiffon'=>array(255,250,205), + 'seashell'=>array(255,245,238), + 'mintcream'=>array(245,255,250), + 'azure'=>array(240,255,255), + 'aliceblue'=>array(240,248,255), + 'lavender'=>array(230,230,250), + 'lavenderblush'=>array(255,240,245), + 'mistyrose'=>array(255,228,225), + 'white'=>array(255,255,255), + 'black'=>array(0,0,0), + 'darkslategray'=>array(47,79,79), + 'dimgray'=>array(105,105,105), + 'slategray'=>array(112,128,144), + 'lightslategray'=>array(119,136,153), + 'gray'=>array(190,190,190), + 'lightgray'=>array(211,211,211), + 'midnightblue'=>array(25,25,112), + 'navy'=>array(0,0,128), + 'indigo'=>array(75,0,130), + 'electricindigo'=>array(102,0,255), + 'deepindigo'=>array(138,43,226), + 'pigmentindigo'=>array(75,0,130), + 'indigodye'=>array(0,65,106), + 'cornflowerblue'=>array(100,149,237), + 'darkslateblue'=>array(72,61,139), + 'slateblue'=>array(106,90,205), + 'mediumslateblue'=>array(123,104,238), + 'lightslateblue'=>array(132,112,255), + 'mediumblue'=>array(0,0,205), + 'royalblue'=>array(65,105,225), + 'blue'=>array(0,0,255), + 'dodgerblue'=>array(30,144,255), + 'deepskyblue'=>array(0,191,255), + 'skyblue'=>array(135,206,235), + 'lightskyblue'=>array(135,206,250), + 'steelblue'=>array(70,130,180), + 'lightred'=>array(211,167,168), + 'lightsteelblue'=>array(176,196,222), + 'lightblue'=>array(173,216,230), + 'powderblue'=>array(176,224,230), + 'paleturquoise'=>array(175,238,238), + 'darkturquoise'=>array(0,206,209), + 'mediumturquoise'=>array(72,209,204), + 'turquoise'=>array(64,224,208), + 'cyan'=>array(0,255,255), + 'lightcyan'=>array(224,255,255), + 'cadetblue'=>array(95,158,160), + 'mediumaquamarine'=>array(102,205,170), + 'aquamarine'=>array(127,255,212), + 'darkgreen'=>array(0,100,0), + 'darkolivegreen'=>array(85,107,47), + 'darkseagreen'=>array(143,188,143), + 'seagreen'=>array(46,139,87), + 'mediumseagreen'=>array(60,179,113), + 'lightseagreen'=>array(32,178,170), + 'palegreen'=>array(152,251,152), + 'springgreen'=>array(0,255,127), + 'lawngreen'=>array(124,252,0), + 'green'=>array(0,255,0), + 'chartreuse'=>array(127,255,0), + 'mediumspringgreen'=>array(0,250,154), + 'greenyellow'=>array(173,255,47), + 'limegreen'=>array(50,205,50), + 'yellowgreen'=>array(154,205,50), + 'forestgreen'=>array(34,139,34), + 'olivedrab'=>array(107,142,35), + 'darkkhaki'=>array(189,183,107), + 'khaki'=>array(240,230,140), + 'palegoldenrod'=>array(238,232,170), + 'lightgoldenrodyellow'=>array(250,250,210), + 'lightyellow'=>array(255,255,200), + 'yellow'=>array(255,255,0), + 'gold'=>array(255,215,0), + 'lightgoldenrod'=>array(238,221,130), + 'goldenrod'=>array(218,165,32), + 'darkgoldenrod'=>array(184,134,11), + 'rosybrown'=>array(188,143,143), + 'indianred'=>array(205,92,92), + 'saddlebrown'=>array(139,69,19), + 'sienna'=>array(160,82,45), + 'peru'=>array(205,133,63), + 'burlywood'=>array(222,184,135), + 'beige'=>array(245,245,220), + 'wheat'=>array(245,222,179), + 'sandybrown'=>array(244,164,96), + 'tan'=>array(210,180,140), + 'chocolate'=>array(210,105,30), + 'firebrick'=>array(178,34,34), + 'brown'=>array(165,42,42), + 'darksalmon'=>array(233,150,122), + 'salmon'=>array(250,128,114), + 'lightsalmon'=>array(255,160,122), + 'orange'=>array(255,165,0), + 'darkorange'=>array(255,140,0), + 'coral'=>array(255,127,80), + 'lightcoral'=>array(240,128,128), + 'tomato'=>array(255,99,71), + 'orangered'=>array(255,69,0), + 'red'=>array(255,0,0), + 'hotpink'=>array(255,105,180), + 'deeppink'=>array(255,20,147), + 'pink'=>array(255,192,203), + 'lightpink'=>array(255,182,193), + 'palevioletred'=>array(219,112,147), + 'maroon'=>array(176,48,96), + 'mediumvioletred'=>array(199,21,133), + 'violetred'=>array(208,32,144), + 'magenta'=>array(255,0,255), + 'violet'=>array(238,130,238), + 'plum'=>array(221,160,221), + 'orchid'=>array(218,112,214), + 'mediumorchid'=>array(186,85,211), + 'darkorchid'=>array(153,50,204), + 'darkviolet'=>array(148,0,211), + 'blueviolet'=>array(138,43,226), + 'purple'=>array(160,32,240), + 'mediumpurple'=>array(147,112,219), + 'thistle'=>array(216,191,216), + 'snow1'=>array(255,250,250), + 'snow2'=>array(238,233,233), + 'snow3'=>array(205,201,201), + 'snow4'=>array(139,137,137), + 'seashell1'=>array(255,245,238), + 'seashell2'=>array(238,229,222), + 'seashell3'=>array(205,197,191), + 'seashell4'=>array(139,134,130), + 'AntiqueWhite1'=>array(255,239,219), + 'AntiqueWhite2'=>array(238,223,204), + 'AntiqueWhite3'=>array(205,192,176), + 'AntiqueWhite4'=>array(139,131,120), + 'bisque1'=>array(255,228,196), + 'bisque2'=>array(238,213,183), + 'bisque3'=>array(205,183,158), + 'bisque4'=>array(139,125,107), + 'peachPuff1'=>array(255,218,185), + 'peachpuff2'=>array(238,203,173), + 'peachpuff3'=>array(205,175,149), + 'peachpuff4'=>array(139,119,101), + 'navajowhite1'=>array(255,222,173), + 'navajowhite2'=>array(238,207,161), + 'navajowhite3'=>array(205,179,139), + 'navajowhite4'=>array(139,121,94), + 'lemonchiffon1'=>array(255,250,205), + 'lemonchiffon2'=>array(238,233,191), + 'lemonchiffon3'=>array(205,201,165), + 'lemonchiffon4'=>array(139,137,112), + 'ivory1'=>array(255,255,240), + 'ivory2'=>array(238,238,224), + 'ivory3'=>array(205,205,193), + 'ivory4'=>array(139,139,131), + 'honeydew'=>array(193,205,193), + 'lavenderblush1'=>array(255,240,245), + 'lavenderblush2'=>array(238,224,229), + 'lavenderblush3'=>array(205,193,197), + 'lavenderblush4'=>array(139,131,134), + 'mistyrose1'=>array(255,228,225), + 'mistyrose2'=>array(238,213,210), + 'mistyrose3'=>array(205,183,181), + 'mistyrose4'=>array(139,125,123), + 'azure1'=>array(240,255,255), + 'azure2'=>array(224,238,238), + 'azure3'=>array(193,205,205), + 'azure4'=>array(131,139,139), + 'slateblue1'=>array(131,111,255), + 'slateblue2'=>array(122,103,238), + 'slateblue3'=>array(105,89,205), + 'slateblue4'=>array(71,60,139), + 'royalblue1'=>array(72,118,255), + 'royalblue2'=>array(67,110,238), + 'royalblue3'=>array(58,95,205), + 'royalblue4'=>array(39,64,139), + 'dodgerblue1'=>array(30,144,255), + 'dodgerblue2'=>array(28,134,238), + 'dodgerblue3'=>array(24,116,205), + 'dodgerblue4'=>array(16,78,139), + 'steelblue1'=>array(99,184,255), + 'steelblue2'=>array(92,172,238), + 'steelblue3'=>array(79,148,205), + 'steelblue4'=>array(54,100,139), + 'deepskyblue1'=>array(0,191,255), + 'deepskyblue2'=>array(0,178,238), + 'deepskyblue3'=>array(0,154,205), + 'deepskyblue4'=>array(0,104,139), + 'skyblue1'=>array(135,206,255), + 'skyblue2'=>array(126,192,238), + 'skyblue3'=>array(108,166,205), + 'skyblue4'=>array(74,112,139), + 'lightskyblue1'=>array(176,226,255), + 'lightskyblue2'=>array(164,211,238), + 'lightskyblue3'=>array(141,182,205), + 'lightskyblue4'=>array(96,123,139), + 'slategray1'=>array(198,226,255), + 'slategray2'=>array(185,211,238), + 'slategray3'=>array(159,182,205), + 'slategray4'=>array(108,123,139), + 'lightsteelblue1'=>array(202,225,255), + 'lightsteelblue2'=>array(188,210,238), + 'lightsteelblue3'=>array(162,181,205), + 'lightsteelblue4'=>array(110,123,139), + 'lightblue1'=>array(191,239,255), + 'lightblue2'=>array(178,223,238), + 'lightblue3'=>array(154,192,205), + 'lightblue4'=>array(104,131,139), + 'lightcyan1'=>array(224,255,255), + 'lightcyan2'=>array(209,238,238), + 'lightcyan3'=>array(180,205,205), + 'lightcyan4'=>array(122,139,139), + 'paleturquoise1'=>array(187,255,255), + 'paleturquoise2'=>array(174,238,238), + 'paleturquoise3'=>array(150,205,205), + 'paleturquoise4'=>array(102,139,139), + 'cadetblue1'=>array(152,245,255), + 'cadetblue2'=>array(142,229,238), + 'cadetblue3'=>array(122,197,205), + 'cadetblue4'=>array(83,134,139), + 'turquoise1'=>array(0,245,255), + 'turquoise2'=>array(0,229,238), + 'turquoise3'=>array(0,197,205), + 'turquoise4'=>array(0,134,139), + 'cyan1'=>array(0,255,255), + 'cyan2'=>array(0,238,238), + 'cyan3'=>array(0,205,205), + 'cyan4'=>array(0,139,139), + 'darkslategray1'=>array(151,255,255), + 'darkslategray2'=>array(141,238,238), + 'darkslategray3'=>array(121,205,205), + 'darkslategray4'=>array(82,139,139), + 'aquamarine1'=>array(127,255,212), + 'aquamarine2'=>array(118,238,198), + 'aquamarine3'=>array(102,205,170), + 'aquamarine4'=>array(69,139,116), + 'darkseagreen1'=>array(193,255,193), + 'darkseagreen2'=>array(180,238,180), + 'darkseagreen3'=>array(155,205,155), + 'darkseagreen4'=>array(105,139,105), + 'seagreen1'=>array(84,255,159), + 'seagreen2'=>array(78,238,148), + 'seagreen3'=>array(67,205,128), + 'seagreen4'=>array(46,139,87), + 'palegreen1'=>array(154,255,154), + 'palegreen2'=>array(144,238,144), + 'palegreen3'=>array(124,205,124), + 'palegreen4'=>array(84,139,84), + 'springgreen1'=>array(0,255,127), + 'springgreen2'=>array(0,238,118), + 'springgreen3'=>array(0,205,102), + 'springgreen4'=>array(0,139,69), + 'chartreuse1'=>array(127,255,0), + 'chartreuse2'=>array(118,238,0), + 'chartreuse3'=>array(102,205,0), + 'chartreuse4'=>array(69,139,0), + 'olivedrab1'=>array(192,255,62), + 'olivedrab2'=>array(179,238,58), + 'olivedrab3'=>array(154,205,50), + 'olivedrab4'=>array(105,139,34), + 'darkolivegreen1'=>array(202,255,112), + 'darkolivegreen2'=>array(188,238,104), + 'darkolivegreen3'=>array(162,205,90), + 'darkolivegreen4'=>array(110,139,61), + 'khaki1'=>array(255,246,143), + 'khaki2'=>array(238,230,133), + 'khaki3'=>array(205,198,115), + 'khaki4'=>array(139,134,78), + 'lightgoldenrod1'=>array(255,236,139), + 'lightgoldenrod2'=>array(238,220,130), + 'lightgoldenrod3'=>array(205,190,112), + 'lightgoldenrod4'=>array(139,129,76), + 'yellow1'=>array(255,255,0), + 'yellow2'=>array(238,238,0), + 'yellow3'=>array(205,205,0), + 'yellow4'=>array(139,139,0), + 'gold1'=>array(255,215,0), + 'gold2'=>array(238,201,0), + 'gold3'=>array(205,173,0), + 'gold4'=>array(139,117,0), + 'goldenrod1'=>array(255,193,37), + 'goldenrod2'=>array(238,180,34), + 'goldenrod3'=>array(205,155,29), + 'goldenrod4'=>array(139,105,20), + 'darkgoldenrod1'=>array(255,185,15), + 'darkgoldenrod2'=>array(238,173,14), + 'darkgoldenrod3'=>array(205,149,12), + 'darkgoldenrod4'=>array(139,101,8), + 'rosybrown1'=>array(255,193,193), + 'rosybrown2'=>array(238,180,180), + 'rosybrown3'=>array(205,155,155), + 'rosybrown4'=>array(139,105,105), + 'indianred1'=>array(255,106,106), + 'indianred2'=>array(238,99,99), + 'indianred3'=>array(205,85,85), + 'indianred4'=>array(139,58,58), + 'sienna1'=>array(255,130,71), + 'sienna2'=>array(238,121,66), + 'sienna3'=>array(205,104,57), + 'sienna4'=>array(139,71,38), + 'burlywood1'=>array(255,211,155), + 'burlywood2'=>array(238,197,145), + 'burlywood3'=>array(205,170,125), + 'burlywood4'=>array(139,115,85), + 'wheat1'=>array(255,231,186), + 'wheat2'=>array(238,216,174), + 'wheat3'=>array(205,186,150), + 'wheat4'=>array(139,126,102), + 'tan1'=>array(255,165,79), + 'tan2'=>array(238,154,73), + 'tan3'=>array(205,133,63), + 'tan4'=>array(139,90,43), + 'chocolate1'=>array(255,127,36), + 'chocolate2'=>array(238,118,33), + 'chocolate3'=>array(205,102,29), + 'chocolate4'=>array(139,69,19), + 'firebrick1'=>array(255,48,48), + 'firebrick2'=>array(238,44,44), + 'firebrick3'=>array(205,38,38), + 'firebrick4'=>array(139,26,26), + 'brown1'=>array(255,64,64), + 'brown2'=>array(238,59,59), + 'brown3'=>array(205,51,51), + 'brown4'=>array(139,35,35), + 'salmon1'=>array(255,140,105), + 'salmon2'=>array(238,130,98), + 'salmon3'=>array(205,112,84), + 'salmon4'=>array(139,76,57), + 'lightsalmon1'=>array(255,160,122), + 'lightsalmon2'=>array(238,149,114), + 'lightsalmon3'=>array(205,129,98), + 'lightsalmon4'=>array(139,87,66), + 'orange1'=>array(255,165,0), + 'orange2'=>array(238,154,0), + 'orange3'=>array(205,133,0), + 'orange4'=>array(139,90,0), + 'darkorange1'=>array(255,127,0), + 'darkorange2'=>array(238,118,0), + 'darkorange3'=>array(205,102,0), + 'darkorange4'=>array(139,69,0), + 'coral1'=>array(255,114,86), + 'coral2'=>array(238,106,80), + 'coral3'=>array(205,91,69), + 'coral4'=>array(139,62,47), + 'tomato1'=>array(255,99,71), + 'tomato2'=>array(238,92,66), + 'tomato3'=>array(205,79,57), + 'tomato4'=>array(139,54,38), + 'orangered1'=>array(255,69,0), + 'orangered2'=>array(238,64,0), + 'orangered3'=>array(205,55,0), + 'orangered4'=>array(139,37,0), + 'deeppink1'=>array(255,20,147), + 'deeppink2'=>array(238,18,137), + 'deeppink3'=>array(205,16,118), + 'deeppink4'=>array(139,10,80), + 'hotpink1'=>array(255,110,180), + 'hotpink2'=>array(238,106,167), + 'hotpink3'=>array(205,96,144), + 'hotpink4'=>array(139,58,98), + 'pink1'=>array(255,181,197), + 'pink2'=>array(238,169,184), + 'pink3'=>array(205,145,158), + 'pink4'=>array(139,99,108), + 'lightpink1'=>array(255,174,185), + 'lightpink2'=>array(238,162,173), + 'lightpink3'=>array(205,140,149), + 'lightpink4'=>array(139,95,101), + 'palevioletred1'=>array(255,130,171), + 'palevioletred2'=>array(238,121,159), + 'palevioletred3'=>array(205,104,137), + 'palevioletred4'=>array(139,71,93), + 'maroon1'=>array(255,52,179), + 'maroon2'=>array(238,48,167), + 'maroon3'=>array(205,41,144), + 'maroon4'=>array(139,28,98), + 'violetred1'=>array(255,62,150), + 'violetred2'=>array(238,58,140), + 'violetred3'=>array(205,50,120), + 'violetred4'=>array(139,34,82), + 'magenta1'=>array(255,0,255), + 'magenta2'=>array(238,0,238), + 'magenta3'=>array(205,0,205), + 'magenta4'=>array(139,0,139), + 'mediumred'=>array(140,34,34), + 'orchid1'=>array(255,131,250), + 'orchid2'=>array(238,122,233), + 'orchid3'=>array(205,105,201), + 'orchid4'=>array(139,71,137), + 'plum1'=>array(255,187,255), + 'plum2'=>array(238,174,238), + 'plum3'=>array(205,150,205), + 'plum4'=>array(139,102,139), + 'mediumorchid1'=>array(224,102,255), + 'mediumorchid2'=>array(209,95,238), + 'mediumorchid3'=>array(180,82,205), + 'mediumorchid4'=>array(122,55,139), + 'darkorchid1'=>array(191,62,255), + 'darkorchid2'=>array(178,58,238), + 'darkorchid3'=>array(154,50,205), + 'darkorchid4'=>array(104,34,139), + 'purple1'=>array(155,48,255), + 'purple2'=>array(145,44,238), + 'purple3'=>array(125,38,205), + 'purple4'=>array(85,26,139), + 'mediumpurple1'=>array(171,130,255), + 'mediumpurple2'=>array(159,121,238), + 'mediumpurple3'=>array(137,104,205), + 'mediumpurple4'=>array(93,71,139), + 'thistle1'=>array(255,225,255), + 'thistle2'=>array(238,210,238), + 'thistle3'=>array(205,181,205), + 'thistle4'=>array(139,123,139), + 'gray1'=>array(10,10,10), + 'gray2'=>array(40,40,30), + 'gray3'=>array(70,70,70), + 'gray4'=>array(100,100,100), + 'gray5'=>array(130,130,130), + 'gray6'=>array(160,160,160), + 'gray7'=>array(190,190,190), + 'gray8'=>array(210,210,210), + 'gray9'=>array(240,240,240), + 'darkgray'=>array(100,100,100), + 'darkblue'=>array(0,0,139), + 'darkcyan'=>array(0,139,139), + 'darkmagenta'=>array(139,0,139), + 'darkred'=>array(139,0,0), + 'silver'=>array(192, 192, 192), + 'eggplant'=>array(144,176,168), + 'lightgreen'=>array(144,238,144)); + } + + + //---------------- + // PUBLIC METHODS + // Colors can be specified as either + // 1. #xxxxxx HTML style + // 2. "colorname" as a named color + // 3. array(r,g,b) RGB triple + // This function translates this to a native RGB format and returns an + // RGB triple. + + function Color($aColor) { + if (is_string($aColor)) { + $matches = array(); + // this regex will parse a color string and fill the $matches array as such: + // 0: the full match if any + // 1: a hex string preceded by a hash, can be 3 characters (#fff) or 6 (#ffffff) (4 or 5 also accepted but...) + // 2,3,4: r,g,b values in hex if the first character of the string is # + // 5: all alpha-numeric characters at the beginning of the string if string does not start with # + // 6: alpha value prefixed by @ if supplied + // 7: alpha value with @ stripped + // 8: adjust value prefixed with : if supplied + // 9: adjust value with : stripped + $regex = '/(#([0-9a-fA-F]{1,2})([0-9a-fA-F]{1,2})([0-9a-fA-F]{1,2}))?([\w]+)?(@([\d\.,]+))?(:([\d\.,]+))?/'; + if(!preg_match($regex, $aColor, $matches)) { + JpGraphError::RaiseL(25078,$aColor);//(" Unknown color: $aColor"); + } + if(empty($matches[5])) { + $r = strlen($matches[2]) == 1 ? $matches[2].$matches[2] : $matches[2]; + $g = strlen($matches[3]) == 1 ? $matches[3].$matches[3] : $matches[3]; + $b = strlen($matches[4]) == 1 ? $matches[4].$matches[4] : $matches[4]; + $r = hexdec($r); + $g = hexdec($g); + $b = hexdec($b); + }else { + if(!isset($this->rgb_table[$matches[5]]) ) { + JpGraphError::RaiseL(25078,$aColor);//(" Unknown color: $aColor"); + } + $r = $this->rgb_table[$matches[5]][0]; + $g = $this->rgb_table[$matches[5]][1]; + $b = $this->rgb_table[$matches[5]][2]; + } + $alpha = isset($matches[7]) ? str_replace(',','.',$matches[7]) : 0; + $adj = isset($matches[9]) ? str_replace(',','.',$matches[9]) : 1.0; + + if( $adj < 0 ) { + JpGraphError::RaiseL(25077);//('Adjustment factor for color must be > 0'); + } + + // Scale adj so that an adj=2 always + // makes the color 100% white (i.e. 255,255,255. + // and adj=1 neutral and adj=0 black. + if( $adj == 1) { + return array($r,$g,$b,$alpha); + } + elseif( $adj > 1 ) { + $m = ($adj-1.0)*(255-min(255,min($r,min($g,$b)))); + return array(min(255,$r+$m), min(255,$g+$m), min(255,$b+$m),$alpha); + } + elseif( $adj < 1 ) { + $m = ($adj-1.0)*max(255,max($r,max($g,$b))); + return array(max(0,$r+$m), max(0,$g+$m), max(0,$b+$m),$alpha); + } + } elseif( is_array($aColor) ) { + if(!isset($aColor[3])) $aColor[3] = 0; + return $aColor; + } + else { + JpGraphError::RaiseL(25079,$aColor,count($aColor));//(" Unknown color specification: $aColor , size=".count($aColor)); + } + } + + // Compare two colors + // return true if equal + function Equal($aCol1,$aCol2) { + $c1 = $this->Color($aCol1); + $c2 = $this->Color($aCol2); + return $c1[0]==$c2[0] && $c1[1]==$c2[1] && $c1[2]==$c2[2] ; + } + + // Allocate a new color in the current image + // Return new color index, -1 if no more colors could be allocated + function Allocate($aColor,$aAlpha=0.0) { + list ($r, $g, $b, $a) = $this->color($aColor); + // If alpha is specified in the color string then this + // takes precedence over the second argument + if( $a > 0 ) { + $aAlpha = $a; + } + if( $aAlpha < 0 || $aAlpha > 1 ) { + JpGraphError::RaiseL(25080);//('Alpha parameter for color must be between 0.0 and 1.0'); + } + return imagecolorresolvealpha($this->img, $r, $g, $b, round($aAlpha * 127)); + } + + // Try to convert an array with three valid numbers to the corresponding hex array + // This is currenly only used in processing the colors for barplots in order to be able + // to handle the case where the color might be specified as an array of colros as well. + // In that case we must be able to find out if an array of values should be interpretated as + // a single color (specifeid as an RGB triple) + static function tryHexConversion($aColor) { + if( is_array( $aColor ) ) { + if( count( $aColor ) == 3 ) { + if( is_numeric($aColor[0]) && is_numeric($aColor[1]) && is_numeric($aColor[2]) ) { + if( ($aColor[0] >= 0 && $aColor[0] <= 255) && + ($aColor[1] >= 0 && $aColor[1] <= 255) && + ($aColor[2] >= 0 && $aColor[2] <= 255) ) { + return sprintf('#%02x%02x%02x',$aColor[0],$aColor[1],$aColor[2]); + } + } + } + } + return $aColor; + } + + // Return a RGB tripple corresponding to a position in the normal light spectrum + // The argumen values is in the range [0, 1] where a value of 0 correponds to blue and + // a value of 1 corresponds to red. Values in betwen is mapped to a linear interpolation + // of the constituting colors in the visible color spectra. + // The $aDynamicRange specified how much of the dynamic range we shold use + // a value of 1.0 give the full dyanmic range and a lower value give more dark + // colors. In the extreme of 0.0 then all colors will be black. + static function GetSpectrum($aVal,$aDynamicRange=1.0) { + if( $aVal < 0 || $aVal > 1.0001 ) { + return array(0,0,0); // Invalid case - just return black + } + + $sat = round(255*$aDynamicRange); + $a = 0.25; + if( $aVal <= 0.25 ) { + return array(0, round($sat*$aVal/$a), $sat); + } + elseif( $aVal <= 0.5 ) { + return array(0, $sat, round($sat-$sat*($aVal-0.25)/$a)); + } + elseif( $aVal <= 0.75 ) { + return array(round($sat*($aVal-0.5)/$a), $sat, 0); + } + else { + return array($sat, round($sat-$sat*($aVal-0.75)/$a), 0); + } + } + +} // Class + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_scatter.php b/ext/jpgraph-3.0.7/src/jpgraph_scatter.php index 141fdfa..f225a62 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_scatter.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_scatter.php @@ -1,242 +1,242 @@ -iSize = $aSize; - $this->iArrowSize = $aArrowSize; - } - - function SetColor($aColor) { - $this->iColor = $aColor; - } - - function Stroke($aImg,$x,$y,$a) { - // First rotate the center coordinates - list($x,$y) = $aImg->Rotate($x,$y); - - $old_origin = $aImg->SetCenter($x,$y); - $old_a = $aImg->a; - $aImg->SetAngle(-$a+$old_a); - - $dx = round($this->iSize/2); - $c = array($x-$dx,$y,$x+$dx,$y); - $x += $dx; - - list($dx,$dy) = $this->isizespec[$this->iArrowSize]; - $ca = array($x,$y,$x-$dx,$y-$dy,$x-$dx,$y+$dy,$x,$y); - - $aImg->SetColor($this->iColor); - $aImg->Polygon($c); - $aImg->FilledPolygon($ca); - - $aImg->SetCenter($old_origin[0],$old_origin[1]); - $aImg->SetAngle($old_a); - } -} - -//=================================================== -// CLASS FieldPlot -// Description: Render a field plot -//=================================================== -class FieldPlot extends Plot { - public $arrow = ''; - private $iAngles = array(); - private $iCallback = ''; - - function __construct($datay,$datax,$angles) { - if( (count($datax) != count($datay)) ) - JpGraphError::RaiseL(20001);//("Fieldplots must have equal number of X and Y points."); - if( (count($datax) != count($angles)) ) - JpGraphError::RaiseL(20002);//("Fieldplots must have an angle specified for each X and Y points."); - - $this->iAngles = $angles; - - parent::__construct($datay,$datax); - $this->value->SetAlign('center','center'); - $this->value->SetMargin(15); - - $this->arrow = new FieldArrow(); - } - - function SetCallback($aFunc) { - $this->iCallback = $aFunc; - } - - function Stroke($img,$xscale,$yscale) { - - // Remeber base color and size - $bc = $this->arrow->iColor; - $bs = $this->arrow->iSize; - $bas = $this->arrow->iArrowSize; - - for( $i=0; $i<$this->numpoints; ++$i ) { - // Skip null values - if( $this->coords[0][$i]==="" ) - continue; - - $f = $this->iCallback; - if( $f != "" ) { - list($cc,$cs,$cas) = call_user_func($f,$this->coords[1][$i],$this->coords[0][$i],$this->iAngles[$i]); - // Fall back on global data if the callback isn't set - if( $cc == "" ) $cc = $bc; - if( $cs == "" ) $cs = $bs; - if( $cas == "" ) $cas = $bas; - $this->arrow->SetColor($cc); - $this->arrow->SetSize($cs,$cas); - } - - $xt = $xscale->Translate($this->coords[1][$i]); - $yt = $yscale->Translate($this->coords[0][$i]); - - $this->arrow->Stroke($img,$xt,$yt,$this->iAngles[$i]); - $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); - } - } - - // Framework function - function Legend($aGraph) { - if( $this->legend != "" ) { - $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - } -} - -//=================================================== -// CLASS ScatterPlot -// Description: Render X and Y plots -//=================================================== -class ScatterPlot extends Plot { - public $mark,$link; - private $impuls = false; - //--------------- - // CONSTRUCTOR - function __construct($datay,$datax=false) { - if( (count($datax) != count($datay)) && is_array($datax)) { - JpGraphError::RaiseL(20003);//("Scatterplot must have equal number of X and Y points."); - } - parent::__construct($datay,$datax); - $this->mark = new PlotMark(); - $this->mark->SetType(MARK_SQUARE); - $this->mark->SetColor($this->color); - $this->value->SetAlign('center','center'); - $this->value->SetMargin(0); - $this->link = new LineProperty(1,'black','solid'); - $this->link->iShow = false; - } - - //--------------- - // PUBLIC METHODS - function SetImpuls($f=true) { - $this->impuls = $f; - } - - function SetStem($f=true) { - $this->impuls = $f; - } - - // Combine the scatter plot points with a line - function SetLinkPoints($aFlag=true,$aColor="black",$aWeight=1,$aStyle='solid') { - $this->link->iShow = $aFlag; - $this->link->iColor = $aColor; - $this->link->iWeight = $aWeight; - $this->link->iStyle = $aStyle; - } - - function Stroke($img,$xscale,$yscale) { - - $ymin=$yscale->scale_abs[0]; - if( $yscale->scale[0] < 0 ) - $yzero=$yscale->Translate(0); - else - $yzero=$yscale->scale_abs[0]; - - $this->csimareas = ''; - for( $i=0; $i<$this->numpoints; ++$i ) { - - // Skip null values - if( $this->coords[0][$i]==='' || $this->coords[0][$i]==='-' || $this->coords[0][$i]==='x') - continue; - - if( isset($this->coords[1]) ) - $xt = $xscale->Translate($this->coords[1][$i]); - else - $xt = $xscale->Translate($i); - $yt = $yscale->Translate($this->coords[0][$i]); - - - if( $this->link->iShow && isset($yt_old) ) { - $img->SetColor($this->link->iColor); - $img->SetLineWeight($this->link->iWeight); - $old = $img->SetLineStyle($this->link->iStyle); - $img->StyleLine($xt_old,$yt_old,$xt,$yt); - $img->SetLineStyle($old); - } - - if( $this->impuls ) { - $img->SetColor($this->color); - $img->SetLineWeight($this->weight); - $img->Line($xt,$yzero,$xt,$yt); - } - - if( !empty($this->csimtargets[$i]) ) { - if( !empty($this->csimwintargets[$i]) ) { - $this->mark->SetCSIMTarget($this->csimtargets[$i],$this->csimwintargets[$i]); - } - else { - $this->mark->SetCSIMTarget($this->csimtargets[$i]); - } - $this->mark->SetCSIMAlt($this->csimalts[$i]); - } - - if( isset($this->coords[1]) ) { - $this->mark->SetCSIMAltVal($this->coords[0][$i],$this->coords[1][$i]); - } - else { - $this->mark->SetCSIMAltVal($this->coords[0][$i],$i); - } - - $this->mark->Stroke($img,$xt,$yt); - - $this->csimareas .= $this->mark->GetCSIMAreas(); - $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); - - $xt_old = $xt; - $yt_old = $yt; - } - } - - // Framework function - function Legend($aGraph) { - if( $this->legend != "" ) { - $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, - $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); - } - } -} // Class -/* EOF */ +iSize = $aSize; + $this->iArrowSize = $aArrowSize; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function Stroke($aImg,$x,$y,$a) { + // First rotate the center coordinates + list($x,$y) = $aImg->Rotate($x,$y); + + $old_origin = $aImg->SetCenter($x,$y); + $old_a = $aImg->a; + $aImg->SetAngle(-$a+$old_a); + + $dx = round($this->iSize/2); + $c = array($x-$dx,$y,$x+$dx,$y); + $x += $dx; + + list($dx,$dy) = $this->isizespec[$this->iArrowSize]; + $ca = array($x,$y,$x-$dx,$y-$dy,$x-$dx,$y+$dy,$x,$y); + + $aImg->SetColor($this->iColor); + $aImg->Polygon($c); + $aImg->FilledPolygon($ca); + + $aImg->SetCenter($old_origin[0],$old_origin[1]); + $aImg->SetAngle($old_a); + } +} + +//=================================================== +// CLASS FieldPlot +// Description: Render a field plot +//=================================================== +class FieldPlot extends Plot { + public $arrow = ''; + private $iAngles = array(); + private $iCallback = ''; + + function __construct($datay,$datax,$angles) { + if( (count($datax) != count($datay)) ) + JpGraphError::RaiseL(20001);//("Fieldplots must have equal number of X and Y points."); + if( (count($datax) != count($angles)) ) + JpGraphError::RaiseL(20002);//("Fieldplots must have an angle specified for each X and Y points."); + + $this->iAngles = $angles; + + parent::__construct($datay,$datax); + $this->value->SetAlign('center','center'); + $this->value->SetMargin(15); + + $this->arrow = new FieldArrow(); + } + + function SetCallback($aFunc) { + $this->iCallback = $aFunc; + } + + function Stroke($img,$xscale,$yscale) { + + // Remeber base color and size + $bc = $this->arrow->iColor; + $bs = $this->arrow->iSize; + $bas = $this->arrow->iArrowSize; + + for( $i=0; $i<$this->numpoints; ++$i ) { + // Skip null values + if( $this->coords[0][$i]==="" ) + continue; + + $f = $this->iCallback; + if( $f != "" ) { + list($cc,$cs,$cas) = call_user_func($f,$this->coords[1][$i],$this->coords[0][$i],$this->iAngles[$i]); + // Fall back on global data if the callback isn't set + if( $cc == "" ) $cc = $bc; + if( $cs == "" ) $cs = $bs; + if( $cas == "" ) $cas = $bas; + $this->arrow->SetColor($cc); + $this->arrow->SetSize($cs,$cas); + } + + $xt = $xscale->Translate($this->coords[1][$i]); + $yt = $yscale->Translate($this->coords[0][$i]); + + $this->arrow->Stroke($img,$xt,$yt,$this->iAngles[$i]); + $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); + } + } + + // Framework function + function Legend($aGraph) { + if( $this->legend != "" ) { + $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } +} + +//=================================================== +// CLASS ScatterPlot +// Description: Render X and Y plots +//=================================================== +class ScatterPlot extends Plot { + public $mark,$link; + private $impuls = false; + //--------------- + // CONSTRUCTOR + function __construct($datay,$datax=false) { + if( (count($datax) != count($datay)) && is_array($datax)) { + JpGraphError::RaiseL(20003);//("Scatterplot must have equal number of X and Y points."); + } + parent::__construct($datay,$datax); + $this->mark = new PlotMark(); + $this->mark->SetType(MARK_SQUARE); + $this->mark->SetColor($this->color); + $this->value->SetAlign('center','center'); + $this->value->SetMargin(0); + $this->link = new LineProperty(1,'black','solid'); + $this->link->iShow = false; + } + + //--------------- + // PUBLIC METHODS + function SetImpuls($f=true) { + $this->impuls = $f; + } + + function SetStem($f=true) { + $this->impuls = $f; + } + + // Combine the scatter plot points with a line + function SetLinkPoints($aFlag=true,$aColor="black",$aWeight=1,$aStyle='solid') { + $this->link->iShow = $aFlag; + $this->link->iColor = $aColor; + $this->link->iWeight = $aWeight; + $this->link->iStyle = $aStyle; + } + + function Stroke($img,$xscale,$yscale) { + + $ymin=$yscale->scale_abs[0]; + if( $yscale->scale[0] < 0 ) + $yzero=$yscale->Translate(0); + else + $yzero=$yscale->scale_abs[0]; + + $this->csimareas = ''; + for( $i=0; $i<$this->numpoints; ++$i ) { + + // Skip null values + if( $this->coords[0][$i]==='' || $this->coords[0][$i]==='-' || $this->coords[0][$i]==='x') + continue; + + if( isset($this->coords[1]) ) + $xt = $xscale->Translate($this->coords[1][$i]); + else + $xt = $xscale->Translate($i); + $yt = $yscale->Translate($this->coords[0][$i]); + + + if( $this->link->iShow && isset($yt_old) ) { + $img->SetColor($this->link->iColor); + $img->SetLineWeight($this->link->iWeight); + $old = $img->SetLineStyle($this->link->iStyle); + $img->StyleLine($xt_old,$yt_old,$xt,$yt); + $img->SetLineStyle($old); + } + + if( $this->impuls ) { + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $img->Line($xt,$yzero,$xt,$yt); + } + + if( !empty($this->csimtargets[$i]) ) { + if( !empty($this->csimwintargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i],$this->csimwintargets[$i]); + } + else { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + } + $this->mark->SetCSIMAlt($this->csimalts[$i]); + } + + if( isset($this->coords[1]) ) { + $this->mark->SetCSIMAltVal($this->coords[0][$i],$this->coords[1][$i]); + } + else { + $this->mark->SetCSIMAltVal($this->coords[0][$i],$i); + } + + $this->mark->Stroke($img,$xt,$yt); + + $this->csimareas .= $this->mark->GetCSIMAreas(); + $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); + + $xt_old = $xt; + $yt_old = $yt; + } + } + + // Framework function + function Legend($aGraph) { + if( $this->legend != "" ) { + $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } +} // Class +/* EOF */ ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_stock.php b/ext/jpgraph-3.0.7/src/jpgraph_stock.php index 45a1368..91f5c81 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_stock.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_stock.php @@ -1,198 +1,198 @@ -iTupleSize ) { - JpGraphError::RaiseL(21001,$this->iTupleSize); - //('Data values for Stock charts must contain an even multiple of '.$this->iTupleSize.' data points.'); - } - parent::__construct($datay,$datax); - $this->numpoints /= $this->iTupleSize; - } - //--------------- - // PUBLIC METHODS - - function SetColor($aColor,$aColor1='white',$aColor2='darkred',$aColor3='darkred') { - $this->color = $aColor; - $this->iStockColor1 = $aColor1; - $this->iStockColor2 = $aColor2; - $this->iStockColor3 = $aColor3; - } - - function SetWidth($aWidth) { - // Make sure it's odd - $this->iWidth = 2*floor($aWidth/2)+1; - } - - function HideEndLines($aHide=true) { - $this->iEndLines = !$aHide; - } - - // Gets called before any axis are stroked - function PreStrokeAdjust($graph) { - if( $this->center ) { - $a=0.5; $b=0.5; - $this->numpoints++; - } else { - $a=0; $b=0; - } - $graph->xaxis->scale->ticks->SetXLabelOffset($a); - $graph->SetTextScaleOff($b); - } - - // Method description - function Stroke($img,$xscale,$yscale) { - $n=$this->numpoints; - if( $this->center ) $n--; - if( isset($this->coords[1]) ) { - if( count($this->coords[1])!=$n ) { - JpGraphError::RaiseL(2003,count($this->coords[1]),$n); - // ("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); - } - else { - $exist_x = true; - } - } - else { - $exist_x = false; - } - - if( $exist_x ) { - $xs=$this->coords[1][0]; - } - else { - $xs=0; - } - - $ts = $this->iTupleSize; - $this->csimareas = ''; - for( $i=0; $i<$n; ++$i) { - - //If value is NULL, then don't draw a bar at all - if ($this->coords[0][$i*$ts] === null) continue; - - if( $exist_x ) { - $x=$this->coords[1][$i]; - if ($x === null) continue; - } - else { - $x=$i; - } - $xt = $xscale->Translate($x); - - $neg = $this->coords[0][$i*$ts] > $this->coords[0][$i*$ts+1] ; - $yopen = $yscale->Translate($this->coords[0][$i*$ts]); - $yclose = $yscale->Translate($this->coords[0][$i*$ts+1]); - $ymin = $yscale->Translate($this->coords[0][$i*$ts+2]); - $ymax = $yscale->Translate($this->coords[0][$i*$ts+3]); - - $dx = floor($this->iWidth/2); - $xl = $xt - $dx; - $xr = $xt + $dx; - - if( $neg ) { - $img->SetColor($this->iStockColor3); - } - else { - $img->SetColor($this->iStockColor1); - } - $img->FilledRectangle($xl,$yopen,$xr,$yclose); - $img->SetLineWeight($this->weight); - if( $neg ) { - $img->SetColor($this->iStockColor2); - } - else { - $img->SetColor($this->color); - } - - $img->Rectangle($xl,$yopen,$xr,$yclose); - - if( $yopen < $yclose ) { - $ytop = $yopen ; - $ybottom = $yclose ; - } - else { - $ytop = $yclose ; - $ybottom = $yopen ; - } - $img->SetColor($this->color); - $img->Line($xt,$ytop,$xt,$ymax); - $img->Line($xt,$ybottom,$xt,$ymin); - - if( $this->iEndLines ) { - $img->Line($xl,$ymax,$xr,$ymax); - $img->Line($xl,$ymin,$xr,$ymin); - } - - // A chance for subclasses to add things to the bar - // for data point i - $this->ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg); - - // Setup image maps - if( !empty($this->csimtargets[$i]) ) { - $this->csimareas.= 'csimareas .= ' href="'.$this->csimtargets[$i].'"'; - if( !empty($this->csimalts[$i]) ) { - $sval=$this->csimalts[$i]; - $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; - } - $this->csimareas.= " />\n"; - } - } - return true; - } - - // A hook for subclasses to modify the plot - function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) {} - -} // Class - -//=================================================== -// CLASS BoxPlot -//=================================================== -class BoxPlot extends StockPlot { - private $iPColor='black',$iNColor='white'; - - function __construct($datay,$datax=false) { - $this->iTupleSize=5; - parent::__construct($datay,$datax); - } - - function SetMedianColor($aPos,$aNeg) { - $this->iPColor = $aPos; - $this->iNColor = $aNeg; - } - - function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) { - if( $neg ) - $img->SetColor($this->iNColor); - else - $img->SetColor($this->iPColor); - - $y = $yscale->Translate($this->coords[0][$i*5+4]); - $img->Line($xl,$y,$xr,$y); - } -} - -/* EOF */ +iTupleSize ) { + JpGraphError::RaiseL(21001,$this->iTupleSize); + //('Data values for Stock charts must contain an even multiple of '.$this->iTupleSize.' data points.'); + } + parent::__construct($datay,$datax); + $this->numpoints /= $this->iTupleSize; + } + //--------------- + // PUBLIC METHODS + + function SetColor($aColor,$aColor1='white',$aColor2='darkred',$aColor3='darkred') { + $this->color = $aColor; + $this->iStockColor1 = $aColor1; + $this->iStockColor2 = $aColor2; + $this->iStockColor3 = $aColor3; + } + + function SetWidth($aWidth) { + // Make sure it's odd + $this->iWidth = 2*floor($aWidth/2)+1; + } + + function HideEndLines($aHide=true) { + $this->iEndLines = !$aHide; + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + if( $this->center ) { + $a=0.5; $b=0.5; + $this->numpoints++; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + } + + // Method description + function Stroke($img,$xscale,$yscale) { + $n=$this->numpoints; + if( $this->center ) $n--; + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$n ) { + JpGraphError::RaiseL(2003,count($this->coords[1]),$n); + // ("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + } + else { + $exist_x = true; + } + } + else { + $exist_x = false; + } + + if( $exist_x ) { + $xs=$this->coords[1][0]; + } + else { + $xs=0; + } + + $ts = $this->iTupleSize; + $this->csimareas = ''; + for( $i=0; $i<$n; ++$i) { + + //If value is NULL, then don't draw a bar at all + if ($this->coords[0][$i*$ts] === null) continue; + + if( $exist_x ) { + $x=$this->coords[1][$i]; + if ($x === null) continue; + } + else { + $x=$i; + } + $xt = $xscale->Translate($x); + + $neg = $this->coords[0][$i*$ts] > $this->coords[0][$i*$ts+1] ; + $yopen = $yscale->Translate($this->coords[0][$i*$ts]); + $yclose = $yscale->Translate($this->coords[0][$i*$ts+1]); + $ymin = $yscale->Translate($this->coords[0][$i*$ts+2]); + $ymax = $yscale->Translate($this->coords[0][$i*$ts+3]); + + $dx = floor($this->iWidth/2); + $xl = $xt - $dx; + $xr = $xt + $dx; + + if( $neg ) { + $img->SetColor($this->iStockColor3); + } + else { + $img->SetColor($this->iStockColor1); + } + $img->FilledRectangle($xl,$yopen,$xr,$yclose); + $img->SetLineWeight($this->weight); + if( $neg ) { + $img->SetColor($this->iStockColor2); + } + else { + $img->SetColor($this->color); + } + + $img->Rectangle($xl,$yopen,$xr,$yclose); + + if( $yopen < $yclose ) { + $ytop = $yopen ; + $ybottom = $yclose ; + } + else { + $ytop = $yclose ; + $ybottom = $yopen ; + } + $img->SetColor($this->color); + $img->Line($xt,$ytop,$xt,$ymax); + $img->Line($xt,$ybottom,$xt,$ymin); + + if( $this->iEndLines ) { + $img->Line($xl,$ymax,$xr,$ymax); + $img->Line($xl,$ymin,$xr,$ymin); + } + + // A chance for subclasses to add things to the bar + // for data point i + $this->ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg); + + // Setup image maps + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas.= 'csimareas .= ' href="'.$this->csimtargets[$i].'"'; + if( !empty($this->csimalts[$i]) ) { + $sval=$this->csimalts[$i]; + $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; + } + $this->csimareas.= " />\n"; + } + } + return true; + } + + // A hook for subclasses to modify the plot + function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) {} + +} // Class + +//=================================================== +// CLASS BoxPlot +//=================================================== +class BoxPlot extends StockPlot { + private $iPColor='black',$iNColor='white'; + + function __construct($datay,$datax=false) { + $this->iTupleSize=5; + parent::__construct($datay,$datax); + } + + function SetMedianColor($aPos,$aNeg) { + $this->iPColor = $aPos; + $this->iNColor = $aNeg; + } + + function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) { + if( $neg ) + $img->SetColor($this->iNColor); + else + $img->SetColor($this->iPColor); + + $y = $yscale->Translate($this->coords[0][$i*5+4]); + $img->Line($xl,$y,$xr,$y); + } +} + +/* EOF */ ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/jpgraph_text.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_text.inc.php index c93846b..8292743 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_text.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_text.inc.php @@ -1,302 +1,302 @@ -t = $aTxt; - $this->x = round($aXAbsPos); - $this->y = round($aYAbsPos); - $this->margin = 0; - } - //--------------- - // PUBLIC METHODS - // Set the string in the text object - function Set($aTxt) { - $this->t = $aTxt; - } - - // Alias for Pos() - function SetPos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") { - //$this->Pos($aXAbsPos,$aYAbsPos,$aHAlign,$aVAlign); - $this->x = $aXAbsPos; - $this->y = $aYAbsPos; - $this->halign = $aHAlign; - $this->valign = $aVAlign; - } - - function SetScalePos($aX,$aY) { - $this->iScalePosX = $aX; - $this->iScalePosY = $aY; - } - - // Specify alignment for the text - function Align($aHAlign,$aVAlign="top",$aParagraphAlign="") { - $this->halign = $aHAlign; - $this->valign = $aVAlign; - if( $aParagraphAlign != "" ) - $this->paragraph_align = $aParagraphAlign; - } - - // Alias - function SetAlign($aHAlign,$aVAlign="top",$aParagraphAlign="") { - $this->Align($aHAlign,$aVAlign,$aParagraphAlign); - } - - // Specifies the alignment for a multi line text - function ParagraphAlign($aAlign) { - $this->paragraph_align = $aAlign; - } - - // Specifies the alignment for a multi line text - function SetParagraphAlign($aAlign) { - $this->paragraph_align = $aAlign; - } - - function SetShadow($aShadowColor='gray',$aShadowWidth=3) { - $this->ishadowwidth=$aShadowWidth; - $this->shadow=$aShadowColor; - $this->boxed=true; - } - - function SetWordWrap($aCol) { - $this->iWordwrap = $aCol ; - } - - // Specify that the text should be boxed. fcolor=frame color, bcolor=border color, - // $shadow=drop shadow should be added around the text. - function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) { - if( $aFrameColor === false ) { - $this->boxed=false; - } - else { - $this->boxed=true; - } - $this->fcolor=$aFrameColor; - $this->bcolor=$aBorderColor; - // For backwards compatibility when shadow was just true or false - if( $aShadowColor === true ) { - $aShadowColor = 'gray'; - } - $this->shadow=$aShadowColor; - $this->icornerradius=$aCornerRadius; - $this->ishadowwidth=$aShadowWidth; - } - - function SetBox2($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) { - $this->iBoxType=2; - $this->SetBox($aFrameColor,$aBorderColor,$aShadowColor,$aCornerRadius,$aShadowWidth); - } - - // Hide the text - function Hide($aHide=true) { - $this->hide=$aHide; - } - - // This looks ugly since it's not a very orthogonal design - // but I added this "inverse" of Hide() to harmonize - // with some classes which I designed more recently (especially) - // jpgraph_gantt - function Show($aShow=true) { - $this->hide=!$aShow; - } - - // Specify font - function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { - $this->font_family=$aFamily; - $this->font_style=$aStyle; - $this->font_size=$aSize; - } - - // Center the text between $left and $right coordinates - function Center($aLeft,$aRight,$aYAbsPos=false) { - $this->x = $aLeft + ($aRight-$aLeft )/2; - $this->halign = "center"; - if( is_numeric($aYAbsPos) ) - $this->y = $aYAbsPos; - } - - // Set text color - function SetColor($aColor) { - $this->color = $aColor; - } - - function SetAngle($aAngle) { - $this->SetOrientation($aAngle); - } - - // Orientation of text. Note only TTF fonts can have an arbitrary angle - function SetOrientation($aDirection=0) { - if( is_numeric($aDirection) ) - $this->dir=$aDirection; - elseif( $aDirection=="h" ) - $this->dir = 0; - elseif( $aDirection=="v" ) - $this->dir = 90; - else - JpGraphError::RaiseL(25051);//(" Invalid direction specified for text."); - } - - // Total width of text - function GetWidth($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $w = $aImg->GetTextWidth($this->t,$this->dir); - return $w; - } - - // Hight of font - function GetFontHeight($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $h = $aImg->GetFontHeight(); - return $h; - - } - - function GetTextHeight($aImg) { - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $h = $aImg->GetTextHeight($this->t,$this->dir); - return $h; - } - - function GetHeight($aImg) { - // Synonym for GetTextHeight() - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $h = $aImg->GetTextHeight($this->t,$this->dir); - return $h; - } - - // Set the margin which will be interpretated differently depending - // on the context. - function SetMargin($aMarg) { - $this->margin = $aMarg; - } - - function StrokeWithScale($aImg,$axscale,$ayscale) { - if( $this->iScalePosX === null || $this->iScalePosY === null ) { - $this->Stroke($aImg); - } - else { - $this->Stroke($aImg, - round($axscale->Translate($this->iScalePosX)), - round($ayscale->Translate($this->iScalePosY))); - } - } - - function SetCSIMTarget($aURITarget,$aAlt='',$aWinTarget='') { - $this->iCSIMtarget = $aURITarget; - $this->iCSIMalt = $aAlt; - $this->iCSIMWinTarget = $aWinTarget; - } - - function GetCSIMareas() { - if( $this->iCSIMtarget !== '' ) { - return $this->iCSIMarea; - } - else { - return ''; - } - } - - // Display text in image - function Stroke($aImg,$x=null,$y=null) { - - if( $x !== null ) $this->x = round($x); - if( $y !== null ) $this->y = round($y); - - // Insert newlines - if( $this->iWordwrap > 0 ) { - $this->t = wordwrap($this->t,$this->iWordwrap,"\n"); - } - - // If position been given as a fraction of the image size - // calculate the absolute position - if( $this->x < 1 && $this->x > 0 ) $this->x *= $aImg->width; - if( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height; - - $aImg->PushColor($this->color); - $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); - $aImg->SetTextAlign($this->halign,$this->valign); - - if( $this->boxed ) { - if( $this->fcolor=="nofill" ) { - $this->fcolor=false; - } - - $oldweight=$aImg->SetLineWeight(1); - - if( $this->iBoxType == 2 && $this->font_family > FF_FONT2+2 ) { - - $bbox = $aImg->StrokeBoxedText2($this->x, $this->y, - $this->t, $this->dir, - $this->fcolor, - $this->bcolor, - $this->shadow, - $this->paragraph_align, - 2,4, - $this->icornerradius, - $this->ishadowwidth); - } - else { - $bbox = $aImg->StrokeBoxedText($this->x,$this->y,$this->t, - $this->dir,$this->fcolor,$this->bcolor,$this->shadow, - $this->paragraph_align,3,3,$this->icornerradius, - $this->ishadowwidth); - } - - $aImg->SetLineWeight($oldweight); - } - else { - $debug=false; - $bbox = $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,$this->paragraph_align,$debug); - } - - // Create CSIM targets - $coords = $bbox[0].','.$bbox[1].','.$bbox[2].','.$bbox[3].','.$bbox[4].','.$bbox[5].','.$bbox[6].','.$bbox[7]; - $this->iCSIMarea = "iCSIMtarget)."\" "; - if( trim($this->iCSIMalt) != '' ) { - $this->iCSIMarea .= " alt=\"".$this->iCSIMalt."\" "; - $this->iCSIMarea .= " title=\"".$this->iCSIMalt."\" "; - } - if( trim($this->iCSIMWinTarget) != '' ) { - $this->iCSIMarea .= " target=\"".$this->iCSIMWinTarget."\" "; - } - $this->iCSIMarea .= " />\n"; - - $aImg->PopColor($this->color); - } -} // Class - - -?> +t = $aTxt; + $this->x = round($aXAbsPos); + $this->y = round($aYAbsPos); + $this->margin = 0; + } + //--------------- + // PUBLIC METHODS + // Set the string in the text object + function Set($aTxt) { + $this->t = $aTxt; + } + + // Alias for Pos() + function SetPos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") { + //$this->Pos($aXAbsPos,$aYAbsPos,$aHAlign,$aVAlign); + $this->x = $aXAbsPos; + $this->y = $aYAbsPos; + $this->halign = $aHAlign; + $this->valign = $aVAlign; + } + + function SetScalePos($aX,$aY) { + $this->iScalePosX = $aX; + $this->iScalePosY = $aY; + } + + // Specify alignment for the text + function Align($aHAlign,$aVAlign="top",$aParagraphAlign="") { + $this->halign = $aHAlign; + $this->valign = $aVAlign; + if( $aParagraphAlign != "" ) + $this->paragraph_align = $aParagraphAlign; + } + + // Alias + function SetAlign($aHAlign,$aVAlign="top",$aParagraphAlign="") { + $this->Align($aHAlign,$aVAlign,$aParagraphAlign); + } + + // Specifies the alignment for a multi line text + function ParagraphAlign($aAlign) { + $this->paragraph_align = $aAlign; + } + + // Specifies the alignment for a multi line text + function SetParagraphAlign($aAlign) { + $this->paragraph_align = $aAlign; + } + + function SetShadow($aShadowColor='gray',$aShadowWidth=3) { + $this->ishadowwidth=$aShadowWidth; + $this->shadow=$aShadowColor; + $this->boxed=true; + } + + function SetWordWrap($aCol) { + $this->iWordwrap = $aCol ; + } + + // Specify that the text should be boxed. fcolor=frame color, bcolor=border color, + // $shadow=drop shadow should be added around the text. + function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) { + if( $aFrameColor === false ) { + $this->boxed=false; + } + else { + $this->boxed=true; + } + $this->fcolor=$aFrameColor; + $this->bcolor=$aBorderColor; + // For backwards compatibility when shadow was just true or false + if( $aShadowColor === true ) { + $aShadowColor = 'gray'; + } + $this->shadow=$aShadowColor; + $this->icornerradius=$aCornerRadius; + $this->ishadowwidth=$aShadowWidth; + } + + function SetBox2($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) { + $this->iBoxType=2; + $this->SetBox($aFrameColor,$aBorderColor,$aShadowColor,$aCornerRadius,$aShadowWidth); + } + + // Hide the text + function Hide($aHide=true) { + $this->hide=$aHide; + } + + // This looks ugly since it's not a very orthogonal design + // but I added this "inverse" of Hide() to harmonize + // with some classes which I designed more recently (especially) + // jpgraph_gantt + function Show($aShow=true) { + $this->hide=!$aShow; + } + + // Specify font + function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { + $this->font_family=$aFamily; + $this->font_style=$aStyle; + $this->font_size=$aSize; + } + + // Center the text between $left and $right coordinates + function Center($aLeft,$aRight,$aYAbsPos=false) { + $this->x = $aLeft + ($aRight-$aLeft )/2; + $this->halign = "center"; + if( is_numeric($aYAbsPos) ) + $this->y = $aYAbsPos; + } + + // Set text color + function SetColor($aColor) { + $this->color = $aColor; + } + + function SetAngle($aAngle) { + $this->SetOrientation($aAngle); + } + + // Orientation of text. Note only TTF fonts can have an arbitrary angle + function SetOrientation($aDirection=0) { + if( is_numeric($aDirection) ) + $this->dir=$aDirection; + elseif( $aDirection=="h" ) + $this->dir = 0; + elseif( $aDirection=="v" ) + $this->dir = 90; + else + JpGraphError::RaiseL(25051);//(" Invalid direction specified for text."); + } + + // Total width of text + function GetWidth($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $w = $aImg->GetTextWidth($this->t,$this->dir); + return $w; + } + + // Hight of font + function GetFontHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetFontHeight(); + return $h; + + } + + function GetTextHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetTextHeight($this->t,$this->dir); + return $h; + } + + function GetHeight($aImg) { + // Synonym for GetTextHeight() + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetTextHeight($this->t,$this->dir); + return $h; + } + + // Set the margin which will be interpretated differently depending + // on the context. + function SetMargin($aMarg) { + $this->margin = $aMarg; + } + + function StrokeWithScale($aImg,$axscale,$ayscale) { + if( $this->iScalePosX === null || $this->iScalePosY === null ) { + $this->Stroke($aImg); + } + else { + $this->Stroke($aImg, + round($axscale->Translate($this->iScalePosX)), + round($ayscale->Translate($this->iScalePosY))); + } + } + + function SetCSIMTarget($aURITarget,$aAlt='',$aWinTarget='') { + $this->iCSIMtarget = $aURITarget; + $this->iCSIMalt = $aAlt; + $this->iCSIMWinTarget = $aWinTarget; + } + + function GetCSIMareas() { + if( $this->iCSIMtarget !== '' ) { + return $this->iCSIMarea; + } + else { + return ''; + } + } + + // Display text in image + function Stroke($aImg,$x=null,$y=null) { + + if( $x !== null ) $this->x = round($x); + if( $y !== null ) $this->y = round($y); + + // Insert newlines + if( $this->iWordwrap > 0 ) { + $this->t = wordwrap($this->t,$this->iWordwrap,"\n"); + } + + // If position been given as a fraction of the image size + // calculate the absolute position + if( $this->x < 1 && $this->x > 0 ) $this->x *= $aImg->width; + if( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height; + + $aImg->PushColor($this->color); + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetTextAlign($this->halign,$this->valign); + + if( $this->boxed ) { + if( $this->fcolor=="nofill" ) { + $this->fcolor=false; + } + + $oldweight=$aImg->SetLineWeight(1); + + if( $this->iBoxType == 2 && $this->font_family > FF_FONT2+2 ) { + + $bbox = $aImg->StrokeBoxedText2($this->x, $this->y, + $this->t, $this->dir, + $this->fcolor, + $this->bcolor, + $this->shadow, + $this->paragraph_align, + 2,4, + $this->icornerradius, + $this->ishadowwidth); + } + else { + $bbox = $aImg->StrokeBoxedText($this->x,$this->y,$this->t, + $this->dir,$this->fcolor,$this->bcolor,$this->shadow, + $this->paragraph_align,3,3,$this->icornerradius, + $this->ishadowwidth); + } + + $aImg->SetLineWeight($oldweight); + } + else { + $debug=false; + $bbox = $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,$this->paragraph_align,$debug); + } + + // Create CSIM targets + $coords = $bbox[0].','.$bbox[1].','.$bbox[2].','.$bbox[3].','.$bbox[4].','.$bbox[5].','.$bbox[6].','.$bbox[7]; + $this->iCSIMarea = "iCSIMtarget)."\" "; + if( trim($this->iCSIMalt) != '' ) { + $this->iCSIMarea .= " alt=\"".$this->iCSIMalt."\" "; + $this->iCSIMarea .= " title=\"".$this->iCSIMalt."\" "; + } + if( trim($this->iCSIMWinTarget) != '' ) { + $this->iCSIMarea .= " target=\"".$this->iCSIMWinTarget."\" "; + } + $this->iCSIMarea .= " />\n"; + + $aImg->PopColor($this->color); + } +} // Class + + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_ttf.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_ttf.inc.php index 1e0d524..f82f214 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_ttf.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_ttf.inc.php @@ -1,617 +1,617 @@ -g2312 == null ) { - include_once 'jpgraph_gb2312.php' ; - $this->g2312 = new GB2312toUTF8(); - } - return $this->g2312->gb2utf8($aTxt); - } - elseif( $aFF === FF_BIG5 ) { - if( !function_exists('iconv') ) { - JpGraphError::RaiseL(25006); - //('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).'); - } - return iconv('BIG5','UTF-8',$aTxt); - } - elseif( ASSUME_EUCJP_ENCODING && - ($aFF == FF_MINCHO || $aFF == FF_GOTHIC || $aFF == FF_PMINCHO || $aFF == FF_PGOTHIC) ) { - if( !function_exists('mb_convert_encoding') ) { - JpGraphError::RaiseL(25127); - } - return mb_convert_encoding($aTxt, 'UTF-8','EUC-JP'); - } - elseif( $aFF == FF_DAVID || $aFF == FF_MIRIAM || $aFF == FF_AHRON ) { - return LanguageConv::heb_iso2uni($aTxt); - } - else - return $aTxt; - } - - // Translate iso encoding to unicode - public static function iso2uni ($isoline){ - $uniline=''; - for ($i=0; $i < strlen($isoline); $i++){ - $thischar=substr($isoline,$i,1); - $charcode=ord($thischar); - $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar; - } - return $uniline; - } - - // Translate greek iso encoding to unicode - public static function gr_iso2uni ($isoline) { - $uniline=''; - for ($i=0; $i < strlen($isoline); $i++) { - $thischar=substr($isoline,$i,1); - $charcode=ord($thischar); - $uniline.=($charcode>179 && $charcode!=183 && $charcode!=187 && $charcode!=189) ? "&#" . (900+($charcode-180)). ";" : $thischar; - } - return $uniline; - } - - // Translate greek win encoding to unicode - public static function gr_win2uni ($winline) { - $uniline=''; - for ($i=0; $i < strlen($winline); $i++) { - $thischar=substr($winline,$i,1); - $charcode=ord($thischar); - if ($charcode==161 || $charcode==162) { - $uniline.="&#" . (740+$charcode). ";"; - } - else { - $uniline.=(($charcode>183 && $charcode!=187 && $charcode!=189) || $charcode==180) ? "&#" . (900+($charcode-180)). ";" : $thischar; - } - } - return $uniline; - } - - public static function heb_iso2uni($isoline) { - $isoline = hebrev($isoline); - $o = ''; - - $n = strlen($isoline); - for($i=0; $i < $n; $i++) { - $c=ord( substr($isoline,$i,1) ); - $o .= ($c > 223) && ($c < 251) ? '&#'.(1264+$c).';' : chr($c); - } - return utf8_encode($o); - } -} - -//============================================================= -// CLASS TTF -// Description: Handle TTF font names and mapping and loading of -// font files -//============================================================= -class TTF { - private $font_files,$style_names; - - function __construct() { - - // String names for font styles to be used in error messages - $this->style_names=array( - FS_NORMAL =>'normal', - FS_BOLD =>'bold', - FS_ITALIC =>'italic', - FS_BOLDITALIC =>'bolditalic'); - - // File names for available fonts - $this->font_files=array( - FF_COURIER => array(FS_NORMAL =>'cour.ttf', - FS_BOLD =>'courbd.ttf', - FS_ITALIC =>'couri.ttf', - FS_BOLDITALIC =>'courbi.ttf' ), - FF_GEORGIA => array(FS_NORMAL =>'georgia.ttf', - FS_BOLD =>'georgiab.ttf', - FS_ITALIC =>'georgiai.ttf', - FS_BOLDITALIC =>'' ), - FF_TREBUCHE =>array(FS_NORMAL =>'trebuc.ttf', - FS_BOLD =>'trebucbd.ttf', - FS_ITALIC =>'trebucit.ttf', - FS_BOLDITALIC =>'trebucbi.ttf' ), - FF_VERDANA => array(FS_NORMAL =>'verdana.ttf', - FS_BOLD =>'verdanab.ttf', - FS_ITALIC =>'verdanai.ttf', - FS_BOLDITALIC =>'' ), - FF_TIMES => array(FS_NORMAL =>'times.ttf', - FS_BOLD =>'timesbd.ttf', - FS_ITALIC =>'timesi.ttf', - FS_BOLDITALIC =>'timesbi.ttf' ), - FF_COMIC => array(FS_NORMAL =>'comic.ttf', - FS_BOLD =>'comicbd.ttf', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - FF_ARIAL => array(FS_NORMAL =>'arial.ttf', - FS_BOLD =>'arialbd.ttf', - FS_ITALIC =>'ariali.ttf', - FS_BOLDITALIC =>'arialbi.ttf' ) , - FF_VERA => array(FS_NORMAL =>'Vera.ttf', - FS_BOLD =>'VeraBd.ttf', - FS_ITALIC =>'VeraIt.ttf', - FS_BOLDITALIC =>'VeraBI.ttf' ), - FF_VERAMONO => array(FS_NORMAL =>'VeraMono.ttf', - FS_BOLD =>'VeraMoBd.ttf', - FS_ITALIC =>'VeraMoIt.ttf', - FS_BOLDITALIC =>'VeraMoBI.ttf' ), - FF_VERASERIF=> array(FS_NORMAL =>'VeraSe.ttf', - FS_BOLD =>'VeraSeBd.ttf', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ) , - - /* Chinese fonts */ - FF_SIMSUN => array( - FS_NORMAL =>'simsun.ttc', - FS_BOLD =>'simhei.ttf', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - FF_CHINESE => array( - FS_NORMAL =>CHINESE_TTF_FONT, - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - FF_BIG5 => array( - FS_NORMAL =>CHINESE_TTF_FONT, - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - /* Japanese fonts */ - FF_MINCHO => array( - FS_NORMAL =>MINCHO_TTF_FONT, - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_PMINCHO => array( - FS_NORMAL =>PMINCHO_TTF_FONT, - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_GOTHIC => array( - FS_NORMAL =>GOTHIC_TTF_FONT, - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_PGOTHIC => array( - FS_NORMAL =>PGOTHIC_TTF_FONT, - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - /* Hebrew fonts */ - FF_DAVID => array( - FS_NORMAL =>'DAVIDNEW.TTF', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_MIRIAM => array( - FS_NORMAL =>'MRIAMY.TTF', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_AHRON => array( - FS_NORMAL =>'ahronbd.ttf', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - /* Misc fonts */ - FF_DIGITAL => array( - FS_NORMAL =>'DIGIRU__.TTF', - FS_BOLD =>'Digirtu_.ttf', - FS_ITALIC =>'Digir___.ttf', - FS_BOLDITALIC =>'DIGIRT__.TTF' ), - - /* This is an experimental font for the speedometer development - FF_SPEEDO => array( - FS_NORMAL =>'Speedo.ttf', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - */ - - FF_COMPUTER => array( - FS_NORMAL =>'COMPUTER.TTF', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_CALCULATOR => array( - FS_NORMAL =>'Triad_xs.ttf', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - /* Dejavu fonts */ - FF_DV_SANSSERIF => array( - FS_NORMAL =>array('DejaVuSans.ttf'), - FS_BOLD =>array('DejaVuSans-Bold.ttf','DejaVuSansBold.ttf'), - FS_ITALIC =>array('DejaVuSans-Oblique.ttf','DejaVuSansOblique.ttf'), - FS_BOLDITALIC =>array('DejaVuSans-BoldOblique.ttf','DejaVuSansBoldOblique.ttf') ), - - FF_DV_SANSSERIFMONO => array( - FS_NORMAL =>array('DejaVuSansMono.ttf','DejaVuMonoSans.ttf'), - FS_BOLD =>array('DejaVuSansMono-Bold.ttf','DejaVuMonoSansBold.ttf'), - FS_ITALIC =>array('DejaVuSansMono-Oblique.ttf','DejaVuMonoSansOblique.ttf'), - FS_BOLDITALIC =>array('DejaVuSansMono-BoldOblique.ttf','DejaVuMonoSansBoldOblique.ttf') ), - - FF_DV_SANSSERIFCOND => array( - FS_NORMAL =>array('DejaVuSansCondensed.ttf','DejaVuCondensedSans.ttf'), - FS_BOLD =>array('DejaVuSansCondensed-Bold.ttf','DejaVuCondensedSansBold.ttf'), - FS_ITALIC =>array('DejaVuSansCondensed-Oblique.ttf','DejaVuCondensedSansOblique.ttf'), - FS_BOLDITALIC =>array('DejaVuSansCondensed-BoldOblique.ttf','DejaVuCondensedSansBoldOblique.ttf') ), - - FF_DV_SERIF => array( - FS_NORMAL =>array('DejaVuSerif.ttf'), - FS_BOLD =>array('DejaVuSerif-Bold.ttf','DejaVuSerifBold.ttf'), - FS_ITALIC =>array('DejaVuSerif-Italic.ttf','DejaVuSerifItalic.ttf'), - FS_BOLDITALIC =>array('DejaVuSerif-BoldItalic.ttf','DejaVuSerifBoldItalic.ttf') ), - - FF_DV_SERIFCOND => array( - FS_NORMAL =>array('DejaVuSerifCondensed.ttf','DejaVuCondensedSerif.ttf'), - FS_BOLD =>array('DejaVuSerifCondensed-Bold.ttf','DejaVuCondensedSerifBold.ttf'), - FS_ITALIC =>array('DejaVuSerifCondensed-Italic.ttf','DejaVuCondensedSerifItalic.ttf'), - FS_BOLDITALIC =>array('DejaVuSerifCondensed-BoldItalic.ttf','DejaVuCondensedSerifBoldItalic.ttf') ), - - - /* Placeholders for defined fonts */ - FF_USERFONT1 => array( - FS_NORMAL =>'', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_USERFONT2 => array( - FS_NORMAL =>'', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - FF_USERFONT3 => array( - FS_NORMAL =>'', - FS_BOLD =>'', - FS_ITALIC =>'', - FS_BOLDITALIC =>'' ), - - ); - } - - //--------------- - // PUBLIC METHODS - // Create the TTF file from the font specification - function File($family,$style=FS_NORMAL) { - $fam = @$this->font_files[$family]; - if( !$fam ) { - JpGraphError::RaiseL(25046,$family);//("Specified TTF font family (id=$family) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/"); - } - $ff = @$fam[$style]; - - if( is_array($ff) ) { - // There are several optional file names. They are tried in order - // and the first one found is used - $n = count($ff); - } else { - $n = 1; - $ff = array($ff); - } - $i = 0; - do { - $f = $ff[$i]; - // All font families are guaranteed to have the normal style - - if( $f==='' ) - JpGraphError::RaiseL(25047,$this->style_names[$style],$this->font_files[$family][FS_NORMAL]);//('Style "'.$this->style_names[$style].'" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.'); - if( !$f ) { - JpGraphError::RaiseL(25048,$fam);//("Unknown font style specification [$fam]."); - } - - if ($family >= FF_MINCHO && $family <= FF_PGOTHIC) { - $f = MBTTF_DIR.$f; - } else { - $f = TTF_DIR.$f; - } - ++$i; - } while( $i < $n && (file_exists($f) === false || is_readable($f) === false) ); - - if( !file_exists($f) ) { - JpGraphError::RaiseL(25049,$f);//("Font file \"$f\" is not readable or does not exist."); - } - return $f; - } - - function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->font_files[FF_USERFONT] = - array(FS_NORMAL => $aNormal, - FS_BOLD => $aBold, - FS_ITALIC => $aItalic, - FS_BOLDITALIC => $aBoldIt ) ; - } - - function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->font_files[FF_USERFONT1] = - array(FS_NORMAL => $aNormal, - FS_BOLD => $aBold, - FS_ITALIC => $aItalic, - FS_BOLDITALIC => $aBoldIt ) ; - } - - function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->font_files[FF_USERFONT2] = - array(FS_NORMAL => $aNormal, - FS_BOLD => $aBold, - FS_ITALIC => $aItalic, - FS_BOLDITALIC => $aBoldIt ) ; - } - - function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') { - $this->font_files[FF_USERFONT3] = - array(FS_NORMAL => $aNormal, - FS_BOLD => $aBold, - FS_ITALIC => $aItalic, - FS_BOLDITALIC => $aBoldIt ) ; - } - -} // Class - - -//============================================================================= -// CLASS SymChar -// Description: Code values for some commonly used characters that -// normally isn't available directly on the keyboard, for example -// mathematical and greek symbols. -//============================================================================= -class SymChar { - static function Get($aSymb,$aCapital=FALSE) { - $iSymbols = array( - /* Greek */ - array('alpha','03B1','0391'), - array('beta','03B2','0392'), - array('gamma','03B3','0393'), - array('delta','03B4','0394'), - array('epsilon','03B5','0395'), - array('zeta','03B6','0396'), - array('ny','03B7','0397'), - array('eta','03B8','0398'), - array('theta','03B8','0398'), - array('iota','03B9','0399'), - array('kappa','03BA','039A'), - array('lambda','03BB','039B'), - array('mu','03BC','039C'), - array('nu','03BD','039D'), - array('xi','03BE','039E'), - array('omicron','03BF','039F'), - array('pi','03C0','03A0'), - array('rho','03C1','03A1'), - array('sigma','03C3','03A3'), - array('tau','03C4','03A4'), - array('upsilon','03C5','03A5'), - array('phi','03C6','03A6'), - array('chi','03C7','03A7'), - array('psi','03C8','03A8'), - array('omega','03C9','03A9'), - /* Money */ - array('euro','20AC'), - array('yen','00A5'), - array('pound','20A4'), - /* Math */ - array('approx','2248'), - array('neq','2260'), - array('not','2310'), - array('def','2261'), - array('inf','221E'), - array('sqrt','221A'), - array('int','222B'), - /* Misc */ - array('copy','00A9'), - array('para','00A7'), - array('tm','2122'), /* Trademark symbol */ - array('rtm','00AE'), /* Registered trademark */ - array('degree','00b0'), - array('lte','2264'), /* Less than or equal */ - array('gte','2265'), /* Greater than or equal */ - - ); - - $n = count($iSymbols); - $i=0; - $found = false; - $aSymb = strtolower($aSymb); - while( $i < $n && !$found ) { - $found = $aSymb === $iSymbols[$i++][0]; - } - if( $found ) { - $ca = $iSymbols[--$i]; - if( $aCapital && count($ca)==3 ) - $s = $ca[2]; - else - $s = $ca[1]; - return sprintf('&#%04d;',hexdec($s)); - } - else - return ''; - } -} - - -?> +g2312 == null ) { + include_once 'jpgraph_gb2312.php' ; + $this->g2312 = new GB2312toUTF8(); + } + return $this->g2312->gb2utf8($aTxt); + } + elseif( $aFF === FF_BIG5 ) { + if( !function_exists('iconv') ) { + JpGraphError::RaiseL(25006); + //('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).'); + } + return iconv('BIG5','UTF-8',$aTxt); + } + elseif( ASSUME_EUCJP_ENCODING && + ($aFF == FF_MINCHO || $aFF == FF_GOTHIC || $aFF == FF_PMINCHO || $aFF == FF_PGOTHIC) ) { + if( !function_exists('mb_convert_encoding') ) { + JpGraphError::RaiseL(25127); + } + return mb_convert_encoding($aTxt, 'UTF-8','EUC-JP'); + } + elseif( $aFF == FF_DAVID || $aFF == FF_MIRIAM || $aFF == FF_AHRON ) { + return LanguageConv::heb_iso2uni($aTxt); + } + else + return $aTxt; + } + + // Translate iso encoding to unicode + public static function iso2uni ($isoline){ + $uniline=''; + for ($i=0; $i < strlen($isoline); $i++){ + $thischar=substr($isoline,$i,1); + $charcode=ord($thischar); + $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar; + } + return $uniline; + } + + // Translate greek iso encoding to unicode + public static function gr_iso2uni ($isoline) { + $uniline=''; + for ($i=0; $i < strlen($isoline); $i++) { + $thischar=substr($isoline,$i,1); + $charcode=ord($thischar); + $uniline.=($charcode>179 && $charcode!=183 && $charcode!=187 && $charcode!=189) ? "&#" . (900+($charcode-180)). ";" : $thischar; + } + return $uniline; + } + + // Translate greek win encoding to unicode + public static function gr_win2uni ($winline) { + $uniline=''; + for ($i=0; $i < strlen($winline); $i++) { + $thischar=substr($winline,$i,1); + $charcode=ord($thischar); + if ($charcode==161 || $charcode==162) { + $uniline.="&#" . (740+$charcode). ";"; + } + else { + $uniline.=(($charcode>183 && $charcode!=187 && $charcode!=189) || $charcode==180) ? "&#" . (900+($charcode-180)). ";" : $thischar; + } + } + return $uniline; + } + + public static function heb_iso2uni($isoline) { + $isoline = hebrev($isoline); + $o = ''; + + $n = strlen($isoline); + for($i=0; $i < $n; $i++) { + $c=ord( substr($isoline,$i,1) ); + $o .= ($c > 223) && ($c < 251) ? '&#'.(1264+$c).';' : chr($c); + } + return utf8_encode($o); + } +} + +//============================================================= +// CLASS TTF +// Description: Handle TTF font names and mapping and loading of +// font files +//============================================================= +class TTF { + private $font_files,$style_names; + + function __construct() { + + // String names for font styles to be used in error messages + $this->style_names=array( + FS_NORMAL =>'normal', + FS_BOLD =>'bold', + FS_ITALIC =>'italic', + FS_BOLDITALIC =>'bolditalic'); + + // File names for available fonts + $this->font_files=array( + FF_COURIER => array(FS_NORMAL =>'cour.ttf', + FS_BOLD =>'courbd.ttf', + FS_ITALIC =>'couri.ttf', + FS_BOLDITALIC =>'courbi.ttf' ), + FF_GEORGIA => array(FS_NORMAL =>'georgia.ttf', + FS_BOLD =>'georgiab.ttf', + FS_ITALIC =>'georgiai.ttf', + FS_BOLDITALIC =>'' ), + FF_TREBUCHE =>array(FS_NORMAL =>'trebuc.ttf', + FS_BOLD =>'trebucbd.ttf', + FS_ITALIC =>'trebucit.ttf', + FS_BOLDITALIC =>'trebucbi.ttf' ), + FF_VERDANA => array(FS_NORMAL =>'verdana.ttf', + FS_BOLD =>'verdanab.ttf', + FS_ITALIC =>'verdanai.ttf', + FS_BOLDITALIC =>'' ), + FF_TIMES => array(FS_NORMAL =>'times.ttf', + FS_BOLD =>'timesbd.ttf', + FS_ITALIC =>'timesi.ttf', + FS_BOLDITALIC =>'timesbi.ttf' ), + FF_COMIC => array(FS_NORMAL =>'comic.ttf', + FS_BOLD =>'comicbd.ttf', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_ARIAL => array(FS_NORMAL =>'arial.ttf', + FS_BOLD =>'arialbd.ttf', + FS_ITALIC =>'ariali.ttf', + FS_BOLDITALIC =>'arialbi.ttf' ) , + FF_VERA => array(FS_NORMAL =>'Vera.ttf', + FS_BOLD =>'VeraBd.ttf', + FS_ITALIC =>'VeraIt.ttf', + FS_BOLDITALIC =>'VeraBI.ttf' ), + FF_VERAMONO => array(FS_NORMAL =>'VeraMono.ttf', + FS_BOLD =>'VeraMoBd.ttf', + FS_ITALIC =>'VeraMoIt.ttf', + FS_BOLDITALIC =>'VeraMoBI.ttf' ), + FF_VERASERIF=> array(FS_NORMAL =>'VeraSe.ttf', + FS_BOLD =>'VeraSeBd.ttf', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ) , + + /* Chinese fonts */ + FF_SIMSUN => array( + FS_NORMAL =>'simsun.ttc', + FS_BOLD =>'simhei.ttf', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_CHINESE => array( + FS_NORMAL =>CHINESE_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_BIG5 => array( + FS_NORMAL =>CHINESE_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Japanese fonts */ + FF_MINCHO => array( + FS_NORMAL =>MINCHO_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_PMINCHO => array( + FS_NORMAL =>PMINCHO_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_GOTHIC => array( + FS_NORMAL =>GOTHIC_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_PGOTHIC => array( + FS_NORMAL =>PGOTHIC_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Hebrew fonts */ + FF_DAVID => array( + FS_NORMAL =>'DAVIDNEW.TTF', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_MIRIAM => array( + FS_NORMAL =>'MRIAMY.TTF', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_AHRON => array( + FS_NORMAL =>'ahronbd.ttf', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Misc fonts */ + FF_DIGITAL => array( + FS_NORMAL =>'DIGIRU__.TTF', + FS_BOLD =>'Digirtu_.ttf', + FS_ITALIC =>'Digir___.ttf', + FS_BOLDITALIC =>'DIGIRT__.TTF' ), + + /* This is an experimental font for the speedometer development + FF_SPEEDO => array( + FS_NORMAL =>'Speedo.ttf', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + */ + + FF_COMPUTER => array( + FS_NORMAL =>'COMPUTER.TTF', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_CALCULATOR => array( + FS_NORMAL =>'Triad_xs.ttf', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Dejavu fonts */ + FF_DV_SANSSERIF => array( + FS_NORMAL =>array('DejaVuSans.ttf'), + FS_BOLD =>array('DejaVuSans-Bold.ttf','DejaVuSansBold.ttf'), + FS_ITALIC =>array('DejaVuSans-Oblique.ttf','DejaVuSansOblique.ttf'), + FS_BOLDITALIC =>array('DejaVuSans-BoldOblique.ttf','DejaVuSansBoldOblique.ttf') ), + + FF_DV_SANSSERIFMONO => array( + FS_NORMAL =>array('DejaVuSansMono.ttf','DejaVuMonoSans.ttf'), + FS_BOLD =>array('DejaVuSansMono-Bold.ttf','DejaVuMonoSansBold.ttf'), + FS_ITALIC =>array('DejaVuSansMono-Oblique.ttf','DejaVuMonoSansOblique.ttf'), + FS_BOLDITALIC =>array('DejaVuSansMono-BoldOblique.ttf','DejaVuMonoSansBoldOblique.ttf') ), + + FF_DV_SANSSERIFCOND => array( + FS_NORMAL =>array('DejaVuSansCondensed.ttf','DejaVuCondensedSans.ttf'), + FS_BOLD =>array('DejaVuSansCondensed-Bold.ttf','DejaVuCondensedSansBold.ttf'), + FS_ITALIC =>array('DejaVuSansCondensed-Oblique.ttf','DejaVuCondensedSansOblique.ttf'), + FS_BOLDITALIC =>array('DejaVuSansCondensed-BoldOblique.ttf','DejaVuCondensedSansBoldOblique.ttf') ), + + FF_DV_SERIF => array( + FS_NORMAL =>array('DejaVuSerif.ttf'), + FS_BOLD =>array('DejaVuSerif-Bold.ttf','DejaVuSerifBold.ttf'), + FS_ITALIC =>array('DejaVuSerif-Italic.ttf','DejaVuSerifItalic.ttf'), + FS_BOLDITALIC =>array('DejaVuSerif-BoldItalic.ttf','DejaVuSerifBoldItalic.ttf') ), + + FF_DV_SERIFCOND => array( + FS_NORMAL =>array('DejaVuSerifCondensed.ttf','DejaVuCondensedSerif.ttf'), + FS_BOLD =>array('DejaVuSerifCondensed-Bold.ttf','DejaVuCondensedSerifBold.ttf'), + FS_ITALIC =>array('DejaVuSerifCondensed-Italic.ttf','DejaVuCondensedSerifItalic.ttf'), + FS_BOLDITALIC =>array('DejaVuSerifCondensed-BoldItalic.ttf','DejaVuCondensedSerifBoldItalic.ttf') ), + + + /* Placeholders for defined fonts */ + FF_USERFONT1 => array( + FS_NORMAL =>'', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_USERFONT2 => array( + FS_NORMAL =>'', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_USERFONT3 => array( + FS_NORMAL =>'', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + ); + } + + //--------------- + // PUBLIC METHODS + // Create the TTF file from the font specification + function File($family,$style=FS_NORMAL) { + $fam = @$this->font_files[$family]; + if( !$fam ) { + JpGraphError::RaiseL(25046,$family);//("Specified TTF font family (id=$family) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/"); + } + $ff = @$fam[$style]; + + if( is_array($ff) ) { + // There are several optional file names. They are tried in order + // and the first one found is used + $n = count($ff); + } else { + $n = 1; + $ff = array($ff); + } + $i = 0; + do { + $f = $ff[$i]; + // All font families are guaranteed to have the normal style + + if( $f==='' ) + JpGraphError::RaiseL(25047,$this->style_names[$style],$this->font_files[$family][FS_NORMAL]);//('Style "'.$this->style_names[$style].'" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.'); + if( !$f ) { + JpGraphError::RaiseL(25048,$fam);//("Unknown font style specification [$fam]."); + } + + if ($family >= FF_MINCHO && $family <= FF_PGOTHIC) { + $f = MBTTF_DIR.$f; + } else { + $f = TTF_DIR.$f; + } + ++$i; + } while( $i < $n && (file_exists($f) === false || is_readable($f) === false) ); + + if( !file_exists($f) ) { + JpGraphError::RaiseL(25049,$f);//("Font file \"$f\" is not readable or does not exist."); + } + return $f; + } + + function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->font_files[FF_USERFONT] = + array(FS_NORMAL => $aNormal, + FS_BOLD => $aBold, + FS_ITALIC => $aItalic, + FS_BOLDITALIC => $aBoldIt ) ; + } + + function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->font_files[FF_USERFONT1] = + array(FS_NORMAL => $aNormal, + FS_BOLD => $aBold, + FS_ITALIC => $aItalic, + FS_BOLDITALIC => $aBoldIt ) ; + } + + function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->font_files[FF_USERFONT2] = + array(FS_NORMAL => $aNormal, + FS_BOLD => $aBold, + FS_ITALIC => $aItalic, + FS_BOLDITALIC => $aBoldIt ) ; + } + + function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') { + $this->font_files[FF_USERFONT3] = + array(FS_NORMAL => $aNormal, + FS_BOLD => $aBold, + FS_ITALIC => $aItalic, + FS_BOLDITALIC => $aBoldIt ) ; + } + +} // Class + + +//============================================================================= +// CLASS SymChar +// Description: Code values for some commonly used characters that +// normally isn't available directly on the keyboard, for example +// mathematical and greek symbols. +//============================================================================= +class SymChar { + static function Get($aSymb,$aCapital=FALSE) { + $iSymbols = array( + /* Greek */ + array('alpha','03B1','0391'), + array('beta','03B2','0392'), + array('gamma','03B3','0393'), + array('delta','03B4','0394'), + array('epsilon','03B5','0395'), + array('zeta','03B6','0396'), + array('ny','03B7','0397'), + array('eta','03B8','0398'), + array('theta','03B8','0398'), + array('iota','03B9','0399'), + array('kappa','03BA','039A'), + array('lambda','03BB','039B'), + array('mu','03BC','039C'), + array('nu','03BD','039D'), + array('xi','03BE','039E'), + array('omicron','03BF','039F'), + array('pi','03C0','03A0'), + array('rho','03C1','03A1'), + array('sigma','03C3','03A3'), + array('tau','03C4','03A4'), + array('upsilon','03C5','03A5'), + array('phi','03C6','03A6'), + array('chi','03C7','03A7'), + array('psi','03C8','03A8'), + array('omega','03C9','03A9'), + /* Money */ + array('euro','20AC'), + array('yen','00A5'), + array('pound','20A4'), + /* Math */ + array('approx','2248'), + array('neq','2260'), + array('not','2310'), + array('def','2261'), + array('inf','221E'), + array('sqrt','221A'), + array('int','222B'), + /* Misc */ + array('copy','00A9'), + array('para','00A7'), + array('tm','2122'), /* Trademark symbol */ + array('rtm','00AE'), /* Registered trademark */ + array('degree','00b0'), + array('lte','2264'), /* Less than or equal */ + array('gte','2265'), /* Greater than or equal */ + + ); + + $n = count($iSymbols); + $i=0; + $found = false; + $aSymb = strtolower($aSymb); + while( $i < $n && !$found ) { + $found = $aSymb === $iSymbols[$i++][0]; + } + if( $found ) { + $ca = $iSymbols[--$i]; + if( $aCapital && count($ca)==3 ) + $s = $ca[2]; + else + $s = $ca[1]; + return sprintf('&#%04d;',hexdec($s)); + } + else + return ''; + } +} + + +?> diff --git a/ext/jpgraph-3.0.7/src/jpgraph_utils.inc.php b/ext/jpgraph-3.0.7/src/jpgraph_utils.inc.php index bd9fc91..a4b40f6 100644 --- a/ext/jpgraph-3.0.7/src/jpgraph_utils.inc.php +++ b/ext/jpgraph-3.0.7/src/jpgraph_utils.inc.php @@ -1,685 +1,685 @@ -iFunc = $aFunc; - $this->iXFunc = $aXFunc; - } - - function E($aXMin,$aXMax,$aSteps=50) { - $this->iMin = $aXMin; - $this->iMax = $aXMax; - $this->iStepSize = ($aXMax-$aXMin)/$aSteps; - - if( $this->iXFunc != '' ) - $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}'; - elseif( $this->iFunc != '' ) - $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;'; - else - JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. '); - - @eval($t); - - // If there is an error in the function specifcation this is the only - // way we can discover that. - if( empty($xa) || empty($ya) ) - JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification '); - - return array($xa,$ya); - } -} - - -//============================================================================= -// CLASS DateScaleUtils -// Description: Help to create a manual date scale -//============================================================================= -define('DSUTILS_MONTH',1); // Major and minor ticks on a monthly basis -define('DSUTILS_MONTH1',1); // Major and minor ticks on a monthly basis -define('DSUTILS_MONTH2',2); // Major ticks on a bi-monthly basis -define('DSUTILS_MONTH3',3); // Major icks on a tri-monthly basis -define('DSUTILS_MONTH6',4); // Major on a six-monthly basis -define('DSUTILS_WEEK1',5); // Major ticks on a weekly basis -define('DSUTILS_WEEK2',6); // Major ticks on a bi-weekly basis -define('DSUTILS_WEEK4',7); // Major ticks on a quod-weekly basis -define('DSUTILS_DAY1',8); // Major ticks on a daily basis -define('DSUTILS_DAY2',9); // Major ticks on a bi-daily basis -define('DSUTILS_DAY4',10); // Major ticks on a qoud-daily basis -define('DSUTILS_YEAR1',11); // Major ticks on a yearly basis -define('DSUTILS_YEAR2',12); // Major ticks on a bi-yearly basis -define('DSUTILS_YEAR5',13); // Major ticks on a five-yearly basis - - -class DateScaleUtils { - public static $iMin=0, $iMax=0; - - private static $starthour,$startmonth, $startday, $startyear; - private static $endmonth, $endyear, $endday; - private static $tickPositions=array(),$minTickPositions=array(); - private static $iUseWeeks = true; - - static function UseWeekFormat($aFlg) { - self::$iUseWeeks = $aFlg; - } - - static function doYearly($aType,$aMinor=false) { - $i=0; $j=0; - $m = self::$startmonth; - $y = self::$startyear; - - if( self::$startday == 1 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); - } - ++$m; - - - switch( $aType ) { - case DSUTILS_YEAR1: - for($y=self::$startyear; $y <= self::$endyear; ++$y ) { - if( $aMinor ) { - while( $m <= 12 ) { - if( !($y == self::$endyear && $m > self::$endmonth) ) { - self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); - } - ++$m; - } - $m=1; - } - self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); - } - break; - case DSUTILS_YEAR2: - $y=self::$startyear; - while( $y <= self::$endyear ) { - self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); - for($k=0; $k < 1; ++$k ) { - ++$y; - if( $aMinor ) { - self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); - } - } - ++$y; - } - break; - case DSUTILS_YEAR5: - $y=self::$startyear; - while( $y <= self::$endyear ) { - self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); - for($k=0; $k < 4; ++$k ) { - ++$y; - if( $aMinor ) { - self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); - } - } - ++$y; - } - break; - } - } - - static function doDaily($aType,$aMinor=false) { - $m = self::$startmonth; - $y = self::$startyear; - $d = self::$startday; - $h = self::$starthour; - $i=0;$j=0; - - if( $h == 0 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); - } - $t = mktime(0,0,0,$m,$d,$y); - - switch($aType) { - case DSUTILS_DAY1: - while( $t <= self::$iMax ) { - $t = strtotime('+1 day',$t); - self::$tickPositions[$i++] = $t; - if( $aMinor ) { - self::$minTickPositions[$j++] = strtotime('+12 hours',$t); - } - } - break; - case DSUTILS_DAY2: - while( $t <= self::$iMax ) { - $t = strtotime('+1 day',$t); - if( $aMinor ) { - self::$minTickPositions[$j++] = $t; - } - $t = strtotime('+1 day',$t); - self::$tickPositions[$i++] = $t; - } - break; - case DSUTILS_DAY4: - while( $t <= self::$iMax ) { - for($k=0; $k < 3; ++$k ) { - $t = strtotime('+1 day',$t); - if( $aMinor ) { - self::$minTickPositions[$j++] = $t; - } - } - $t = strtotime('+1 day',$t); - self::$tickPositions[$i++] = $t; - } - break; - } - } - - static function doWeekly($aType,$aMinor=false) { - $hpd = 3600*24; - $hpw = 3600*24*7; - // Find out week number of min date - $thursday = self::$iMin + $hpd * (3 - (date('w', self::$iMin) + 6) % 7); - $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; - $daynumber = date('w',self::$iMin); - if( $daynumber == 0 ) $daynumber = 7; - $m = self::$startmonth; - $y = self::$startyear; - $d = self::$startday; - $i=0;$j=0; - // The assumption is that the weeks start on Monday. If the first day - // is later in the week then the first week tick has to be on the following - // week. - if( $daynumber == 1 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); - $t = mktime(0,0,0,$m,$d,$y) + $hpw; - } - else { - $t = mktime(0,0,0,$m,$d,$y) + $hpd*(8-$daynumber); - } - - switch($aType) { - case DSUTILS_WEEK1: - $cnt=0; - break; - case DSUTILS_WEEK2: - $cnt=1; - break; - case DSUTILS_WEEK4: - $cnt=3; - break; - } - while( $t <= self::$iMax ) { - self::$tickPositions[$i++] = $t; - for($k=0; $k < $cnt; ++$k ) { - $t += $hpw; - if( $aMinor ) { - self::$minTickPositions[$j++] = $t; - } - } - $t += $hpw; - } - } - - static function doMonthly($aType,$aMinor=false) { - $monthcount=0; - $m = self::$startmonth; - $y = self::$startyear; - $i=0; $j=0; - - // Skip the first month label if it is before the startdate - if( self::$startday == 1 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); - $monthcount=1; - } - if( $aType == 1 ) { - if( self::$startday < 15 ) { - self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); - } - } - ++$m; - - // Loop through all the years included in the scale - for($y=self::$startyear; $y <= self::$endyear; ++$y ) { - // Loop through all the months. There are three cases to consider: - // 1. We are in the first year and must start with the startmonth - // 2. We are in the end year and we must stop at last month of the scale - // 3. A year in between where we run through all the 12 months - $stopmonth = $y == self::$endyear ? self::$endmonth : 12; - while( $m <= $stopmonth ) { - switch( $aType ) { - case DSUTILS_MONTH1: - // Set minor tick at the middle of the month - if( $aMinor ) { - if( $m <= $stopmonth ) { - if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) - self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); - } - } - // Major at month - // Get timestamp of first hour of first day in each month - self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); - - break; - case DSUTILS_MONTH2: - if( $aMinor ) { - // Set minor tick at start of each month - self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); - } - - // Major at every second month - // Get timestamp of first hour of first day in each month - if( $monthcount % 2 == 0 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); - } - break; - case DSUTILS_MONTH3: - if( $aMinor ) { - // Set minor tick at start of each month - self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); - } - // Major at every third month - // Get timestamp of first hour of first day in each month - if( $monthcount % 3 == 0 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); - } - break; - case DSUTILS_MONTH6: - if( $aMinor ) { - // Set minor tick at start of each month - self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); - } - // Major at every third month - // Get timestamp of first hour of first day in each month - if( $monthcount % 6 == 0 ) { - self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); - } - break; - } - ++$m; - ++$monthcount; - } - $m=1; - } - - // For the case where all dates are within the same month - // we want to make sure we have at least two ticks on the scale - // since the scale want work properly otherwise - if(self::$startmonth == self::$endmonth && self::$startyear == self::$endyear && $aType==1 ) { - self::$tickPositions[$i++] = mktime(0 ,0 ,0, self::$startmonth + 1, 1, self::$startyear); - } - - return array(self::$tickPositions,self::$minTickPositions); - } - - static function GetTicks($aData,$aType=1,$aMinor=false,$aEndPoints=false) { - $n = count($aData); - return self::GetTicksFromMinMax($aData[0],$aData[$n-1],$aType,$aMinor,$aEndPoints); - } - - static function GetAutoTicks($aMin,$aMax,$aMaxTicks=10,$aMinor=false) { - $diff = $aMax - $aMin; - $spd = 3600*24; - $spw = $spd*7; - $spm = $spd*30; - $spy = $spd*352; - - if( self::$iUseWeeks ) - $w = 'W'; - else - $w = 'd M'; - - // Decision table for suitable scales - // First value: Main decision point - // Second value: Array of formatting depending on divisor for wanted max number of ticks. ,.. - $tt = array( - array($spw, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',-1,DSUTILS_DAY4,'d M')), - array($spm, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,-1,DSUTILS_WEEK2,$w)), - array($spy, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,14,DSUTILS_WEEK2,$w,30,DSUTILS_MONTH1,'M',60,DSUTILS_MONTH2,'M',-1,DSUTILS_MONTH3,'M')), - array(-1, array(30,DSUTILS_MONTH1,'M-Y',60,DSUTILS_MONTH2,'M-Y',90,DSUTILS_MONTH3,'M-Y',180,DSUTILS_MONTH6,'M-Y',352,DSUTILS_YEAR1,'Y',704,DSUTILS_YEAR2,'Y',-1,DSUTILS_YEAR5,'Y'))); - - $ntt = count($tt); - $nd = floor($diff/$spd); - for($i=0; $i < $ntt; ++$i ) { - if( $diff <= $tt[$i][0] || $i==$ntt-1) { - $t = $tt[$i][1]; - $n = count($t)/3; - for( $j=0; $j < $n; ++$j ) { - if( $nd/$t[3*$j] <= $aMaxTicks || $j==$n-1) { - $type = $t[3*$j+1]; - $fs = $t[3*$j+2]; - list($tickPositions,$minTickPositions) = self::GetTicksFromMinMax($aMin,$aMax,$type,$aMinor); - return array($fs,$tickPositions,$minTickPositions,$type); - } - } - } - } - } - - static function GetTicksFromMinMax($aMin,$aMax,$aType,$aMinor=false,$aEndPoints=false) { - self::$starthour = date('G',$aMin); - self::$startmonth = date('n',$aMin); - self::$startday = date('j',$aMin); - self::$startyear = date('Y',$aMin); - self::$endmonth = date('n',$aMax); - self::$endyear = date('Y',$aMax); - self::$endday = date('j',$aMax); - self::$iMin = $aMin; - self::$iMax = $aMax; - - if( $aType <= DSUTILS_MONTH6 ) { - self::doMonthly($aType,$aMinor); - } - elseif( $aType <= DSUTILS_WEEK4 ) { - self::doWeekly($aType,$aMinor); - } - elseif( $aType <= DSUTILS_DAY4 ) { - self::doDaily($aType,$aMinor); - } - elseif( $aType <= DSUTILS_YEAR5 ) { - self::doYearly($aType,$aMinor); - } - else { - JpGraphError::RaiseL(24003); - } - // put a label at the very left data pos - if( $aEndPoints ) { - $tickPositions[$i++] = $aData[0]; - } - - // put a label at the very right data pos - if( $aEndPoints ) { - $tickPositions[$i] = $aData[$n-1]; - } - - return array(self::$tickPositions,self::$minTickPositions); - } -} - -//============================================================================= -// Class ReadFileData -//============================================================================= -Class ReadFileData { - //---------------------------------------------------------------------------- - // Desciption: - // Read numeric data from a file. - // Each value should be separated by either a new line or by a specified - // separator character (default is ','). - // Before returning the data each value is converted to a proper float - // value. The routine is robust in the sense that non numeric data in the - // file will be discarded. - // - // Returns: - // The number of data values read on success, FALSE on failure - //---------------------------------------------------------------------------- - static function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) { - $rh = @fopen($aFile,'r'); - if( $rh === false ) { - return false; - } - $tmp = array(); - $lineofdata = fgetcsv($rh, 1000, ','); - while ( $lineofdata !== FALSE) { - $tmp = array_merge($tmp,$lineofdata); - $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar); - } - fclose($rh); - - // Now make sure that all data is numeric. By default - // all data is read as strings - $n = count($tmp); - $aData = array(); - $cnt=0; - for($i=0; $i < $n; ++$i) { - if( $tmp[$i] !== "" ) { - $aData[$cnt++] = floatval($tmp[$i]); - } - } - return $cnt; - } - - //---------------------------------------------------------------------------- - // Desciption: - // Read numeric data from a file. - // Each value should be separated by either a new line or by a specified - // separator character (default is ','). - // Before returning the data each value is converted to a proper float - // value. The routine is robust in the sense that non numeric data in the - // file will be discarded. - // - // Options: - // 'separator' => ',', - // 'enclosure' => '"', - // 'readlength' => 1024, - // 'ignore_first' => false, - // 'first_as_key' => false - // 'escape' => '\', # PHP >= 5.3 only - // - // Returns: - // The number of lines read on success, FALSE on failure - //---------------------------------------------------------------------------- - static function FromCSV2($aFile, &$aData, $aOptions = array()) { - $aDefaults = array( - 'separator' => ',', - 'enclosure' => chr(34), - 'escape' => chr(92), - 'readlength' => 1024, - 'ignore_first' => false, - 'first_as_key' => false - ); - - $aOptions = array_merge( - $aDefaults, is_array($aOptions) ? $aOptions : array()); - - if( $aOptions['first_as_key'] ) { - $aOptions['ignore_first'] = true; - } - - $rh = @fopen($aFile, 'r'); - - if( $rh === false ) { - return false; - } - - $aData = array(); - $aLine = fgetcsv($rh, - $aOptions['readlength'], - $aOptions['separator'], - $aOptions['enclosure'] - /*, $aOptions['escape'] # PHP >= 5.3 only */ - ); - - // Use numeric array keys for the columns by default - // If specified use first lines values as assoc keys instead - $keys = array_keys($aLine); - if( $aOptions['first_as_key'] ) { - $keys = array_values($aLine); - } - - $num_lines = 0; - $num_cols = count($aLine); - - while ($aLine !== false) { - if( is_array($aLine) && count($aLine) != $num_cols ) { - JpGraphError::RaiseL(24004); - // 'ReadCSV2: Column count mismatch in %s line %d' - } - - // fgetcsv returns NULL for empty lines - if( !is_null($aLine) ) { - $num_lines++; - - if( !($aOptions['ignore_first'] && $num_lines == 1) && is_numeric($aLine[0]) ) { - for( $i = 0; $i < $num_cols; $i++ ) { - $aData[ $keys[$i] ][] = floatval($aLine[$i]); - } - } - } - - $aLine = fgetcsv($rh, - $aOptions['readlength'], - $aOptions['separator'], - $aOptions['enclosure'] - /*, $aOptions['escape'] # PHP >= 5.3 only*/ - ); - } - - fclose($rh); - - if( $aOptions['ignore_first'] ) { - $num_lines--; - } - - return $num_lines; - } - - // Read data from two columns in a plain text file - static function From2Col($aFile, $aCol1, $aCol2, $aSepChar=' ') { - $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); - if( $lines === false ) { - return false; - } - $s = '/[\s]+/'; - if( $aSepChar == ',' ) { - $s = '/[\s]*,[\s]*/'; - } - elseif( $aSepChar == ';' ) { - $s = '/[\s]*;[\s]*/'; - } - foreach( $lines as $line => $datarow ) { - $split = preg_split($s,$datarow); - $aCol1[] = floatval(trim($split[0])); - $aCol2[] = floatval(trim($split[1])); - } - - return count($lines); - } - - // Read data from one columns in a plain text file - static function From1Col($aFile, $aCol1) { - $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); - if( $lines === false ) { - return false; - } - foreach( $lines as $line => $datarow ) { - $aCol1[] = floatval(trim($datarow)); - } - - return count($lines); - } - - static function FromMatrix($aFile,$aSepChar=' ') { - $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); - if( $lines === false ) { - return false; - } - $mat = array(); - $reg = '/'.$aSepChar.'/'; - foreach( $lines as $line => $datarow ) { - $row = preg_split($reg,trim($datarow)); - foreach ($row as $key => $cell ) { - $row[$key] = floatval(trim($cell)); - } - $mat[] = $row; - } - return $mat; - } - - -} - -define('__LR_EPSILON', 1.0e-8); -//============================================================================= -// Class LinearRegression -//============================================================================= -class LinearRegression { - private $ix=array(),$iy=array(); - private $ib=0, $ia=0; - private $icalculated=false; - public $iDet=0, $iCorr=0, $iStdErr=0; - - public function __construct($aDataX,$aDataY) { - if( count($aDataX) !== count($aDataY) ) { - JpGraph::Raise('LinearRegression: X and Y data array must be of equal length.'); - } - $this->ix = $aDataX; - $this->iy = $aDataY; - } - - public function Calc() { - - $this->icalculated = true; - - $n = count($this->ix); - $sx2 = 0 ; - $sy2 = 0 ; - $sxy = 0 ; - $sx = 0 ; - $sy = 0 ; - - for( $i=0; $i < $n; ++$i ) { - $sx2 += $this->ix[$i] * $this->ix[$i]; - $sy2 += $this->iy[$i] * $this->iy[$i]; - $sxy += $this->ix[$i] * $this->iy[$i]; - $sx += $this->ix[$i]; - $sy += $this->iy[$i]; - } - - if( $n*$sx2 - $sx*$sx > __LR_EPSILON ) { - $this->ib = ($n*$sxy - $sx*$sy) / ( $n*$sx2 - $sx*$sx ); - $this->ia = ( $sy - $this->ib*$sx ) / $n; - - $sx = $this->ib * ( $sxy - $sx*$sy/$n ); - $sy2 = $sy2 - $sy*$sy/$n; - $sy = $sy2 - $sx; - - $this->iDet = $sx / $sy2; - $this->iCorr = sqrt($this->iDet); - if( $n > 2 ) { - $this->iStdErr = sqrt( $sy / ($n-2) ); - } - else { - $this->iStdErr = NAN ; - } - } - else { - $this->ib = 0; - $this->ia = 0; - } - - } - - public function GetAB() { - if( $this->icalculated == false ) - $this->Calc(); - return array($this->ia, $this->ib); - } - - public function GetStat() { - if( $this->icalculated == false ) - $this->Calc(); - return array($this->iStdErr, $this->iCorr, $this->iDet); - } - - public function GetY($aMinX, $aMaxX, $aStep=1) { - if( $this->icalculated == false ) - $this->Calc(); - - $yy = array(); - $i = 0; - for( $x=$aMinX; $x <= $aMaxX; $x += $aStep ) { - $xx[$i ] = $x; - $yy[$i++] = $this->ia + $this->ib * $x; - } - - return array($xx,$yy); - } - -} - +iFunc = $aFunc; + $this->iXFunc = $aXFunc; + } + + function E($aXMin,$aXMax,$aSteps=50) { + $this->iMin = $aXMin; + $this->iMax = $aXMax; + $this->iStepSize = ($aXMax-$aXMin)/$aSteps; + + if( $this->iXFunc != '' ) + $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}'; + elseif( $this->iFunc != '' ) + $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;'; + else + JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. '); + + @eval($t); + + // If there is an error in the function specifcation this is the only + // way we can discover that. + if( empty($xa) || empty($ya) ) + JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification '); + + return array($xa,$ya); + } +} + + +//============================================================================= +// CLASS DateScaleUtils +// Description: Help to create a manual date scale +//============================================================================= +define('DSUTILS_MONTH',1); // Major and minor ticks on a monthly basis +define('DSUTILS_MONTH1',1); // Major and minor ticks on a monthly basis +define('DSUTILS_MONTH2',2); // Major ticks on a bi-monthly basis +define('DSUTILS_MONTH3',3); // Major icks on a tri-monthly basis +define('DSUTILS_MONTH6',4); // Major on a six-monthly basis +define('DSUTILS_WEEK1',5); // Major ticks on a weekly basis +define('DSUTILS_WEEK2',6); // Major ticks on a bi-weekly basis +define('DSUTILS_WEEK4',7); // Major ticks on a quod-weekly basis +define('DSUTILS_DAY1',8); // Major ticks on a daily basis +define('DSUTILS_DAY2',9); // Major ticks on a bi-daily basis +define('DSUTILS_DAY4',10); // Major ticks on a qoud-daily basis +define('DSUTILS_YEAR1',11); // Major ticks on a yearly basis +define('DSUTILS_YEAR2',12); // Major ticks on a bi-yearly basis +define('DSUTILS_YEAR5',13); // Major ticks on a five-yearly basis + + +class DateScaleUtils { + public static $iMin=0, $iMax=0; + + private static $starthour,$startmonth, $startday, $startyear; + private static $endmonth, $endyear, $endday; + private static $tickPositions=array(),$minTickPositions=array(); + private static $iUseWeeks = true; + + static function UseWeekFormat($aFlg) { + self::$iUseWeeks = $aFlg; + } + + static function doYearly($aType,$aMinor=false) { + $i=0; $j=0; + $m = self::$startmonth; + $y = self::$startyear; + + if( self::$startday == 1 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + ++$m; + + + switch( $aType ) { + case DSUTILS_YEAR1: + for($y=self::$startyear; $y <= self::$endyear; ++$y ) { + if( $aMinor ) { + while( $m <= 12 ) { + if( !($y == self::$endyear && $m > self::$endmonth) ) { + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + ++$m; + } + $m=1; + } + self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); + } + break; + case DSUTILS_YEAR2: + $y=self::$startyear; + while( $y <= self::$endyear ) { + self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); + for($k=0; $k < 1; ++$k ) { + ++$y; + if( $aMinor ) { + self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); + } + } + ++$y; + } + break; + case DSUTILS_YEAR5: + $y=self::$startyear; + while( $y <= self::$endyear ) { + self::$tickPositions[$i++] = mktime(0,0,0,1,1,$y); + for($k=0; $k < 4; ++$k ) { + ++$y; + if( $aMinor ) { + self::$minTickPositions[$j++] = mktime(0,0,0,1,1,$y); + } + } + ++$y; + } + break; + } + } + + static function doDaily($aType,$aMinor=false) { + $m = self::$startmonth; + $y = self::$startyear; + $d = self::$startday; + $h = self::$starthour; + $i=0;$j=0; + + if( $h == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); + } + $t = mktime(0,0,0,$m,$d,$y); + + switch($aType) { + case DSUTILS_DAY1: + while( $t <= self::$iMax ) { + $t = strtotime('+1 day',$t); + self::$tickPositions[$i++] = $t; + if( $aMinor ) { + self::$minTickPositions[$j++] = strtotime('+12 hours',$t); + } + } + break; + case DSUTILS_DAY2: + while( $t <= self::$iMax ) { + $t = strtotime('+1 day',$t); + if( $aMinor ) { + self::$minTickPositions[$j++] = $t; + } + $t = strtotime('+1 day',$t); + self::$tickPositions[$i++] = $t; + } + break; + case DSUTILS_DAY4: + while( $t <= self::$iMax ) { + for($k=0; $k < 3; ++$k ) { + $t = strtotime('+1 day',$t); + if( $aMinor ) { + self::$minTickPositions[$j++] = $t; + } + } + $t = strtotime('+1 day',$t); + self::$tickPositions[$i++] = $t; + } + break; + } + } + + static function doWeekly($aType,$aMinor=false) { + $hpd = 3600*24; + $hpw = 3600*24*7; + // Find out week number of min date + $thursday = self::$iMin + $hpd * (3 - (date('w', self::$iMin) + 6) % 7); + $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; + $daynumber = date('w',self::$iMin); + if( $daynumber == 0 ) $daynumber = 7; + $m = self::$startmonth; + $y = self::$startyear; + $d = self::$startday; + $i=0;$j=0; + // The assumption is that the weeks start on Monday. If the first day + // is later in the week then the first week tick has to be on the following + // week. + if( $daynumber == 1 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,$d,$y); + $t = mktime(0,0,0,$m,$d,$y) + $hpw; + } + else { + $t = mktime(0,0,0,$m,$d,$y) + $hpd*(8-$daynumber); + } + + switch($aType) { + case DSUTILS_WEEK1: + $cnt=0; + break; + case DSUTILS_WEEK2: + $cnt=1; + break; + case DSUTILS_WEEK4: + $cnt=3; + break; + } + while( $t <= self::$iMax ) { + self::$tickPositions[$i++] = $t; + for($k=0; $k < $cnt; ++$k ) { + $t += $hpw; + if( $aMinor ) { + self::$minTickPositions[$j++] = $t; + } + } + $t += $hpw; + } + } + + static function doMonthly($aType,$aMinor=false) { + $monthcount=0; + $m = self::$startmonth; + $y = self::$startyear; + $i=0; $j=0; + + // Skip the first month label if it is before the startdate + if( self::$startday == 1 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + $monthcount=1; + } + if( $aType == 1 ) { + if( self::$startday < 15 ) { + self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); + } + } + ++$m; + + // Loop through all the years included in the scale + for($y=self::$startyear; $y <= self::$endyear; ++$y ) { + // Loop through all the months. There are three cases to consider: + // 1. We are in the first year and must start with the startmonth + // 2. We are in the end year and we must stop at last month of the scale + // 3. A year in between where we run through all the 12 months + $stopmonth = $y == self::$endyear ? self::$endmonth : 12; + while( $m <= $stopmonth ) { + switch( $aType ) { + case DSUTILS_MONTH1: + // Set minor tick at the middle of the month + if( $aMinor ) { + if( $m <= $stopmonth ) { + if( !($y==self::$endyear && $m==$stopmonth && self::$endday < 15) ) + self::$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y); + } + } + // Major at month + // Get timestamp of first hour of first day in each month + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + + break; + case DSUTILS_MONTH2: + if( $aMinor ) { + // Set minor tick at start of each month + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + + // Major at every second month + // Get timestamp of first hour of first day in each month + if( $monthcount % 2 == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + break; + case DSUTILS_MONTH3: + if( $aMinor ) { + // Set minor tick at start of each month + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + // Major at every third month + // Get timestamp of first hour of first day in each month + if( $monthcount % 3 == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + break; + case DSUTILS_MONTH6: + if( $aMinor ) { + // Set minor tick at start of each month + self::$minTickPositions[$j++] = mktime(0,0,0,$m,1,$y); + } + // Major at every third month + // Get timestamp of first hour of first day in each month + if( $monthcount % 6 == 0 ) { + self::$tickPositions[$i++] = mktime(0,0,0,$m,1,$y); + } + break; + } + ++$m; + ++$monthcount; + } + $m=1; + } + + // For the case where all dates are within the same month + // we want to make sure we have at least two ticks on the scale + // since the scale want work properly otherwise + if(self::$startmonth == self::$endmonth && self::$startyear == self::$endyear && $aType==1 ) { + self::$tickPositions[$i++] = mktime(0 ,0 ,0, self::$startmonth + 1, 1, self::$startyear); + } + + return array(self::$tickPositions,self::$minTickPositions); + } + + static function GetTicks($aData,$aType=1,$aMinor=false,$aEndPoints=false) { + $n = count($aData); + return self::GetTicksFromMinMax($aData[0],$aData[$n-1],$aType,$aMinor,$aEndPoints); + } + + static function GetAutoTicks($aMin,$aMax,$aMaxTicks=10,$aMinor=false) { + $diff = $aMax - $aMin; + $spd = 3600*24; + $spw = $spd*7; + $spm = $spd*30; + $spy = $spd*352; + + if( self::$iUseWeeks ) + $w = 'W'; + else + $w = 'd M'; + + // Decision table for suitable scales + // First value: Main decision point + // Second value: Array of formatting depending on divisor for wanted max number of ticks. ,.. + $tt = array( + array($spw, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',-1,DSUTILS_DAY4,'d M')), + array($spm, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,-1,DSUTILS_WEEK2,$w)), + array($spy, array(1,DSUTILS_DAY1,'d M',2,DSUTILS_DAY2,'d M',4,DSUTILS_DAY4,'d M',7,DSUTILS_WEEK1,$w,14,DSUTILS_WEEK2,$w,30,DSUTILS_MONTH1,'M',60,DSUTILS_MONTH2,'M',-1,DSUTILS_MONTH3,'M')), + array(-1, array(30,DSUTILS_MONTH1,'M-Y',60,DSUTILS_MONTH2,'M-Y',90,DSUTILS_MONTH3,'M-Y',180,DSUTILS_MONTH6,'M-Y',352,DSUTILS_YEAR1,'Y',704,DSUTILS_YEAR2,'Y',-1,DSUTILS_YEAR5,'Y'))); + + $ntt = count($tt); + $nd = floor($diff/$spd); + for($i=0; $i < $ntt; ++$i ) { + if( $diff <= $tt[$i][0] || $i==$ntt-1) { + $t = $tt[$i][1]; + $n = count($t)/3; + for( $j=0; $j < $n; ++$j ) { + if( $nd/$t[3*$j] <= $aMaxTicks || $j==$n-1) { + $type = $t[3*$j+1]; + $fs = $t[3*$j+2]; + list($tickPositions,$minTickPositions) = self::GetTicksFromMinMax($aMin,$aMax,$type,$aMinor); + return array($fs,$tickPositions,$minTickPositions,$type); + } + } + } + } + } + + static function GetTicksFromMinMax($aMin,$aMax,$aType,$aMinor=false,$aEndPoints=false) { + self::$starthour = date('G',$aMin); + self::$startmonth = date('n',$aMin); + self::$startday = date('j',$aMin); + self::$startyear = date('Y',$aMin); + self::$endmonth = date('n',$aMax); + self::$endyear = date('Y',$aMax); + self::$endday = date('j',$aMax); + self::$iMin = $aMin; + self::$iMax = $aMax; + + if( $aType <= DSUTILS_MONTH6 ) { + self::doMonthly($aType,$aMinor); + } + elseif( $aType <= DSUTILS_WEEK4 ) { + self::doWeekly($aType,$aMinor); + } + elseif( $aType <= DSUTILS_DAY4 ) { + self::doDaily($aType,$aMinor); + } + elseif( $aType <= DSUTILS_YEAR5 ) { + self::doYearly($aType,$aMinor); + } + else { + JpGraphError::RaiseL(24003); + } + // put a label at the very left data pos + if( $aEndPoints ) { + $tickPositions[$i++] = $aData[0]; + } + + // put a label at the very right data pos + if( $aEndPoints ) { + $tickPositions[$i] = $aData[$n-1]; + } + + return array(self::$tickPositions,self::$minTickPositions); + } +} + +//============================================================================= +// Class ReadFileData +//============================================================================= +Class ReadFileData { + //---------------------------------------------------------------------------- + // Desciption: + // Read numeric data from a file. + // Each value should be separated by either a new line or by a specified + // separator character (default is ','). + // Before returning the data each value is converted to a proper float + // value. The routine is robust in the sense that non numeric data in the + // file will be discarded. + // + // Returns: + // The number of data values read on success, FALSE on failure + //---------------------------------------------------------------------------- + static function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) { + $rh = @fopen($aFile,'r'); + if( $rh === false ) { + return false; + } + $tmp = array(); + $lineofdata = fgetcsv($rh, 1000, ','); + while ( $lineofdata !== FALSE) { + $tmp = array_merge($tmp,$lineofdata); + $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar); + } + fclose($rh); + + // Now make sure that all data is numeric. By default + // all data is read as strings + $n = count($tmp); + $aData = array(); + $cnt=0; + for($i=0; $i < $n; ++$i) { + if( $tmp[$i] !== "" ) { + $aData[$cnt++] = floatval($tmp[$i]); + } + } + return $cnt; + } + + //---------------------------------------------------------------------------- + // Desciption: + // Read numeric data from a file. + // Each value should be separated by either a new line or by a specified + // separator character (default is ','). + // Before returning the data each value is converted to a proper float + // value. The routine is robust in the sense that non numeric data in the + // file will be discarded. + // + // Options: + // 'separator' => ',', + // 'enclosure' => '"', + // 'readlength' => 1024, + // 'ignore_first' => false, + // 'first_as_key' => false + // 'escape' => '\', # PHP >= 5.3 only + // + // Returns: + // The number of lines read on success, FALSE on failure + //---------------------------------------------------------------------------- + static function FromCSV2($aFile, &$aData, $aOptions = array()) { + $aDefaults = array( + 'separator' => ',', + 'enclosure' => chr(34), + 'escape' => chr(92), + 'readlength' => 1024, + 'ignore_first' => false, + 'first_as_key' => false + ); + + $aOptions = array_merge( + $aDefaults, is_array($aOptions) ? $aOptions : array()); + + if( $aOptions['first_as_key'] ) { + $aOptions['ignore_first'] = true; + } + + $rh = @fopen($aFile, 'r'); + + if( $rh === false ) { + return false; + } + + $aData = array(); + $aLine = fgetcsv($rh, + $aOptions['readlength'], + $aOptions['separator'], + $aOptions['enclosure'] + /*, $aOptions['escape'] # PHP >= 5.3 only */ + ); + + // Use numeric array keys for the columns by default + // If specified use first lines values as assoc keys instead + $keys = array_keys($aLine); + if( $aOptions['first_as_key'] ) { + $keys = array_values($aLine); + } + + $num_lines = 0; + $num_cols = count($aLine); + + while ($aLine !== false) { + if( is_array($aLine) && count($aLine) != $num_cols ) { + JpGraphError::RaiseL(24004); + // 'ReadCSV2: Column count mismatch in %s line %d' + } + + // fgetcsv returns NULL for empty lines + if( !is_null($aLine) ) { + $num_lines++; + + if( !($aOptions['ignore_first'] && $num_lines == 1) && is_numeric($aLine[0]) ) { + for( $i = 0; $i < $num_cols; $i++ ) { + $aData[ $keys[$i] ][] = floatval($aLine[$i]); + } + } + } + + $aLine = fgetcsv($rh, + $aOptions['readlength'], + $aOptions['separator'], + $aOptions['enclosure'] + /*, $aOptions['escape'] # PHP >= 5.3 only*/ + ); + } + + fclose($rh); + + if( $aOptions['ignore_first'] ) { + $num_lines--; + } + + return $num_lines; + } + + // Read data from two columns in a plain text file + static function From2Col($aFile, $aCol1, $aCol2, $aSepChar=' ') { + $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if( $lines === false ) { + return false; + } + $s = '/[\s]+/'; + if( $aSepChar == ',' ) { + $s = '/[\s]*,[\s]*/'; + } + elseif( $aSepChar == ';' ) { + $s = '/[\s]*;[\s]*/'; + } + foreach( $lines as $line => $datarow ) { + $split = preg_split($s,$datarow); + $aCol1[] = floatval(trim($split[0])); + $aCol2[] = floatval(trim($split[1])); + } + + return count($lines); + } + + // Read data from one columns in a plain text file + static function From1Col($aFile, $aCol1) { + $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if( $lines === false ) { + return false; + } + foreach( $lines as $line => $datarow ) { + $aCol1[] = floatval(trim($datarow)); + } + + return count($lines); + } + + static function FromMatrix($aFile,$aSepChar=' ') { + $lines = @file($aFile,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); + if( $lines === false ) { + return false; + } + $mat = array(); + $reg = '/'.$aSepChar.'/'; + foreach( $lines as $line => $datarow ) { + $row = preg_split($reg,trim($datarow)); + foreach ($row as $key => $cell ) { + $row[$key] = floatval(trim($cell)); + } + $mat[] = $row; + } + return $mat; + } + + +} + +define('__LR_EPSILON', 1.0e-8); +//============================================================================= +// Class LinearRegression +//============================================================================= +class LinearRegression { + private $ix=array(),$iy=array(); + private $ib=0, $ia=0; + private $icalculated=false; + public $iDet=0, $iCorr=0, $iStdErr=0; + + public function __construct($aDataX,$aDataY) { + if( count($aDataX) !== count($aDataY) ) { + JpGraph::Raise('LinearRegression: X and Y data array must be of equal length.'); + } + $this->ix = $aDataX; + $this->iy = $aDataY; + } + + public function Calc() { + + $this->icalculated = true; + + $n = count($this->ix); + $sx2 = 0 ; + $sy2 = 0 ; + $sxy = 0 ; + $sx = 0 ; + $sy = 0 ; + + for( $i=0; $i < $n; ++$i ) { + $sx2 += $this->ix[$i] * $this->ix[$i]; + $sy2 += $this->iy[$i] * $this->iy[$i]; + $sxy += $this->ix[$i] * $this->iy[$i]; + $sx += $this->ix[$i]; + $sy += $this->iy[$i]; + } + + if( $n*$sx2 - $sx*$sx > __LR_EPSILON ) { + $this->ib = ($n*$sxy - $sx*$sy) / ( $n*$sx2 - $sx*$sx ); + $this->ia = ( $sy - $this->ib*$sx ) / $n; + + $sx = $this->ib * ( $sxy - $sx*$sy/$n ); + $sy2 = $sy2 - $sy*$sy/$n; + $sy = $sy2 - $sx; + + $this->iDet = $sx / $sy2; + $this->iCorr = sqrt($this->iDet); + if( $n > 2 ) { + $this->iStdErr = sqrt( $sy / ($n-2) ); + } + else { + $this->iStdErr = NAN ; + } + } + else { + $this->ib = 0; + $this->ia = 0; + } + + } + + public function GetAB() { + if( $this->icalculated == false ) + $this->Calc(); + return array($this->ia, $this->ib); + } + + public function GetStat() { + if( $this->icalculated == false ) + $this->Calc(); + return array($this->iStdErr, $this->iCorr, $this->iDet); + } + + public function GetY($aMinX, $aMaxX, $aStep=1) { + if( $this->icalculated == false ) + $this->Calc(); + + $yy = array(); + $i = 0; + for( $x=$aMinX; $x <= $aMaxX; $x += $aStep ) { + $xx[$i ] = $x; + $yy[$i++] = $this->ia + $this->ib * $x; + } + + return array($xx,$yy); + } + +} + ?> \ No newline at end of file diff --git a/ext/jpgraph-3.0.7/src/lang/de.inc.php b/ext/jpgraph-3.0.7/src/lang/de.inc.php index c92e549..425c864 100644 --- a/ext/jpgraph-3.0.7/src/lang/de.inc.php +++ b/ext/jpgraph-3.0.7/src/lang/de.inc.php @@ -1,542 +1,542 @@ -,) -$_jpg_messages = array( - -/* -** Headers wurden bereits gesendet - Fehler. Dies wird als HTML formatiert, weil es direkt als text zurueckgesendet wird -*/ -10 => array('
      JpGraph Fehler: -HTTP header wurden bereits gesendet.
      Fehler in der Datei %s in der Zeile %d.
      ErklÀrung:
      HTTP header wurden bereits zum Browser gesendet, wobei die Daten als Text gekennzeichnet wurden, bevor die Bibliothek die Chance hatte, seinen Bild-HTTP-Header zum Browser zu schicken. Dies verhindert, dass die Bibliothek Bilddaten zum Browser schicken kann (weil sie vom Browser als Text interpretiert wÃŒrden und daher nur Mist dargestellt wÃŒrde).

      Wahrscheinlich steht Text im Skript bevor Graph::Stroke() aufgerufen wird. Wenn dieser Text zum Browser gesendet wird, nimmt dieser an, dass die gesamten Daten aus Text bestehen. Such nach irgendwelchem Text, auch nach Leerzeichen und ZeilenumbrÃŒchen, die eventuell bereits zum Browser gesendet wurden.

      Zum Beispiel ist ein oft auftretender Fehler, eine Leerzeile am Anfang der Datei oder vor Graph::Stroke() zu lassen."<?php".

      ',2), - -/* -** Setup Fehler -*/ -11 => array('Es wurde kein Pfad fÃŒr CACHE_DIR angegeben. Bitte gib einen Pfad CACHE_DIR in der Datei jpg-config.inc an.',0), -12 => array('Es wurde kein Pfad fÃŒr TTF_DIR angegeben und der Pfad kann nicht automatisch ermittelt werden. Bitte gib den Pfad in der Datei jpg-config.inc an.',0), -13 => array('The installed PHP version (%s) is not compatible with this release of the library. The library requires at least PHP version %s',2), - -/* -** jpgraph_bar -*/ - -2001 => array('Die Anzahl der Farben ist nicht gleich der Anzahl der Vorlagen in BarPlot::SetPattern().',0), -2002 => array('Unbekannte Vorlage im Aufruf von BarPlot::SetPattern().',0), -2003 => array('Anzahl der X- und Y-Koordinaten sind nicht identisch. Anzahl der X-Koordinaten: %d; Anzahl der Y-Koordinaten: %d.',2), -2004 => array('Alle Werte fÃŒr ein Balkendiagramm (barplot) mÃŒssen numerisch sein. Du hast den Wert nr [%d] == %s angegeben.',2), -2005 => array('Du hast einen leeren Vektor fÃŒr die Schattierungsfarben im Balkendiagramm (barplot) angegeben.',0), -2006 => array('Unbekannte Position fÃŒr die Werte der Balken: %s.',1), -2007 => array('Kann GroupBarPlot nicht aus einem leeren Vektor erzeugen.',0), -2008 => array('GroupBarPlot Element nbr %d wurde nicht definiert oder ist leer.',0), -2009 => array('Eins der Objekte, das an GroupBar weitergegeben wurde ist kein Balkendiagramm (BarPlot). Versichere Dich, dass Du den GroupBarPlot aus einem Vektor von Balkendiagrammen (barplot) oder AccBarPlot-Objekten erzeugst. (Class = %s)',1), -2010 => array('Kann AccBarPlot nicht aus einem leeren Vektor erzeugen.',0), -2011 => array('AccBarPlot-Element nbr %d wurde nicht definiert oder ist leer.',1), -2012 => array('Eins der Objekte, das an AccBar weitergegeben wurde ist kein Balkendiagramm (barplot). Versichere Dich, dass Du den AccBar-Plot aus einem Vektor von Balkendiagrammen (barplot) erzeugst. (Class=%s)',1), -2013 => array('Du hast einen leeren Vektor fÃŒr die Schattierungsfarben im Balkendiagramm (barplot) angegeben.',0), -2014 => array('Die Anzahl der Datenpunkte jeder Datenreihe in AccBarPlot muss gleich sein.',0), -2015 => array('Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-coordinates',0), - - -/* -** jpgraph_date -*/ - -3001 => array('Es ist nur möglich, entweder SetDateAlign() oder SetTimeAlign() zu benutzen, nicht beides!',0), - -/* -** jpgraph_error -*/ - -4002 => array('Fehler bei den Eingabedaten von LineErrorPlot. Die Anzahl der Datenpunkte mus ein Mehrfaches von drei sein!',0), - -/* -** jpgraph_flags -*/ - -5001 => array('Unbekannte Flaggen-Größe (%d).',1), -5002 => array('Der Flaggen-Index %s existiert nicht.',1), -5003 => array('Es wurde eine ungÃŒltige Ordnungszahl (%d) fÃŒr den Flaggen-Index angegeben.',1), -5004 => array('Der Landesname %s hat kein korrespondierendes Flaggenbild. Die Flagge mag existieren, abr eventuell unter einem anderen Namen, z.B. versuche "united states" statt "usa".',1), - - -/* -** jpgraph_gantt -*/ - -6001 => array('Interner Fehler. Die Höhe fÃŒr ActivityTitles ist < 0.',0), -6002 => array('Es dÃŒrfen keine negativen Werte fÃŒr die Gantt-Diagramm-Dimensionen angegeben werden. Verwende 0, wenn die Dimensionen automatisch ermittelt werden sollen.',0), -6003 => array('UngÃŒltiges Format fÃŒr den Bedingungs-Parameter bei Index=%d in CreateSimple(). Der Parameter muss bei index 0 starten und Vektoren in der Form (Row,Constrain-To,Constrain-Type) enthalten.',1), -6004 => array('UngÃŒltiges Format fÃŒr den Fortschritts-Parameter bei Index=%d in CreateSimple(). Der Parameter muss bei Index 0 starten und Vektoren in der Form (Row,Progress) enthalten.',1), -6005 => array('SetScale() ist nicht sinnvoll bei Gantt-Diagrammen.',0), -6006 => array('Das Gantt-Diagramm kann nicht automatisch skaliert werden. Es existieren keine AktivitÀten mit Termin. [GetBarMinMax() start >= n]',0), -6007 => array('PlausibiltÀtsprÃŒfung fÃŒr die automatische Gantt-Diagramm-Größe schlug fehl. Entweder die Breite (=%d) oder die Höhe (=%d) ist größer als MAX_GANTTIMG_SIZE. Dies kann möglicherweise durch einen falschen Wert bei einer AktivitÀt hervorgerufen worden sein.',2), -6008 => array('Du hast eine Bedingung angegeben von Reihe=%d bis Reihe=%d, die keine AktivitÀt hat.',2), -6009 => array('Unbekannter Bedingungstyp von Reihe=%d bis Reihe=%d',2), -6010 => array('UngÃŒltiger Icon-Index fÃŒr das eingebaute Gantt-Icon [%d]',1), -6011 => array('Argument fÃŒr IconImage muss entweder ein String oder ein Integer sein.',0), -6012 => array('Unbekannter Typ bei der Gantt-Objekt-Title-Definition.',0), -6015 => array('UngÃŒltige vertikale Position %d',1), -6016 => array('Der eingegebene Datums-String (%s) fÃŒr eine Gantt-AktivitÀt kann nicht interpretiert werden. Versichere Dich, dass es ein gÃŒltiger Datumsstring ist, z.B. 2005-04-23 13:30',1), -6017 => array('Unbekannter Datumstyp in GanttScale (%s).',1), -6018 => array('Intervall fÃŒr Minuten muss ein gerader Teiler einer Stunde sein, z.B. 1,5,10,12,15,20,30, etc. Du hast ein Intervall von %d Minuten angegeben.',1), -6019 => array('Die vorhandene Breite (%d) fÃŒr die Minuten ist zu klein, um angezeigt zu werden. Bitte benutze die automatische Größenermittlung oder vergrößere die Breite des Diagramms.',1), -6020 => array('Das Intervall fÃŒr die Stunden muss ein gerader Teiler eines Tages sein, z.B. 0:30, 1:00, 1:30, 4:00, etc. Du hast ein Intervall von %d eingegeben.',1), -6021 => array('Unbekanntes Format fÃŒr die Woche.',0), -6022 => array('Die Gantt-Skala wurde nicht eingegeben.',0), -6023 => array('Wenn Du sowohl Stunden als auch Minuten anzeigen lassen willst, muss das Stunden-Interval gleich 1 sein (anderenfalls ist es nicht sinnvoll, Minuten anzeigen zu lassen).',0), -6024 => array('Das CSIM-Ziel muss als String angegeben werden. Der Start des Ziels ist: %d',1), -6025 => array('Der CSIM-Alt-Text muss als String angegeben werden. Der Beginn des Alt-Textes ist: %d',1), -6027 => array('Der Fortschrittswert muss im Bereich [0, 1] liegen.',0), -6028 => array('Die eingegebene Höhe (%d) fÃŒr GanttBar ist nicht im zulÀssigen Bereich.',1), -6029 => array('Der Offset fÃŒr die vertikale Linie muss im Bereich [0,1] sein.',0), -6030 => array('Unbekannte Pfeilrichtung fÃŒr eine Verbindung.',0), -6031 => array('Unbekannter Pfeiltyp fÃŒr eine Verbindung.',0), -6032 => array('Interner Fehler: Unbekannter Pfadtyp (=%d) fÃŒr eine Verbindung.',1), -6033 => array('Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)',0), - -/* -** jpgraph_gradient -*/ - -7001 => array('Unbekannter Gradiententyp (=%d).',1), - -/* -** jpgraph_iconplot -*/ - -8001 => array('Der Mix-Wert fÃŒr das Icon muss zwischen 0 und 100 sein.',0), -8002 => array('Die Ankerposition fÃŒr Icons muss entweder "top", "bottom", "left", "right" oder "center" sein.',0), -8003 => array('Es ist nicht möglich, gleichzeitig ein Bild und eine Landesflagge fÃŒr dasselbe Icon zu definieren',0), -8004 => array('Wenn Du Landesflaggen benutzen willst, musst Du die Datei "jpgraph_flags.php" hinzufÃŒgen (per include).',0), - -/* -** jpgraph_imgtrans -*/ - -9001 => array('Der Wert fÃŒr die Bildtransformation ist außerhalb des zulÀssigen Bereichs. Der verschwindende Punkt am Horizont muss als Wert zwischen 0 und 1 angegeben werden.',0), - -/* -** jpgraph_lineplot -*/ - -10001 => array('Die Methode LinePlot::SetFilled() sollte nicht mehr benutzt werden. Benutze lieber SetFillColor()',0), -10002 => array('Der Plot ist zu kompliziert fÃŒr FastLineStroke. Benutze lieber den StandardStroke()',0), -10003 => array('Each plot in an accumulated lineplot must have the same number of data points.',0), -/* -** jpgraph_log -*/ - -11001 => array('Deine Daten enthalten nicht-numerische Werte.',0), -11002 => array('Negative Werte können nicht fÃŒr logarithmische Achsen verwendet werden.',0), -11003 => array('Deine Daten enthalten nicht-numerische Werte.',0), -11004 => array('Skalierungsfehler fÃŒr die logarithmische Achse. Es gibt ein Problem mit den Daten der Achse. Der größte Wert muss größer sein als Null. Es ist mathematisch nicht möglich, einen Wert gleich Null in der Skala zu haben.',0), -11005 => array('Das Tick-Intervall fÃŒr die logarithmische Achse ist nicht definiert. Lösche jeden Aufruf von SetTextLabelStart() oder SetTextTickInterval() bei der logarithmischen Achse.',0), - -/* -** jpgraph_mgraph -*/ - -12001 => array("Du benutzt GD 2.x und versuchst ein Nicht-Truecolor-Bild als Hintergrundbild zu benutzen. Um Hintergrundbilder mit GD 2.x zu benutzen, ist es notwendig Truecolor zu aktivieren, indem die USE_TRUECOLOR-Konstante auf TRUE gesetzt wird. Wegen eines Bugs in GD 2.0.1 ist die QualitÀt der Truetype-Schriften sehr schlecht, wenn man Truetype-Schriften mit Truecolor-Bildern verwendet.",0), -12002 => array('UngÃŒltiger Dateiname fÃŒr MGraph::SetBackgroundImage() : %s. Die Datei muss eine gÃŒltige Dateierweiterung haben (jpg,gif,png), wenn die automatische Typerkennung verwendet wird.',1), -12003 => array('Unbekannte Dateierweiterung (%s) in MGraph::SetBackgroundImage() fÃŒr Dateiname: %s',2), -12004 => array('Das Bildformat des Hintergrundbildes (%s) wird von Deiner System-Konfiguration nicht unterstÃŒtzt. ',1), -12005 => array('Das Hintergrundbild kann nicht gelesen werden: %s',1), -12006 => array('Es wurden ungÃŒltige Größen fÃŒr Breite oder Höhe beim Erstellen des Bildes angegeben, (Breite=%d, Höhe=%d)',2), -12007 => array('Das Argument fÃŒr MGraph::Add() ist nicht gÃŒltig fÃŒr GD.',0), -12008 => array('Deine PHP- (und GD-lib-) Installation scheint keine bekannten Bildformate zu unterstÃŒtzen.',0), -12009 => array('Deine PHP-Installation unterstÃŒtzt das gewÀhlte Bildformat nicht: %s',1), -12010 => array('Es konnte kein Bild als Datei %s erzeugt werden. ÜberprÃŒfe, ob Du die entsprechenden Schreibrechte im aktuellen Verzeichnis hast.',1), -12011 => array('Es konnte kein Truecolor-Bild erzeugt werden. ÜberprÃŒfe, ob Du wirklich die GD2-Bibliothek installiert hast.',0), -12012 => array('Es konnte kein Bild erzeugt werden. ÜberprÃŒfe, ob Du wirklich die GD2-Bibliothek installiert hast.',0), - -/* -** jpgraph_pie3d -*/ - -14001 => array('Pie3D::ShowBorder(). Missbilligte Funktion. Benutze Pie3D::SetEdge(), um die Ecken der TortenstÃŒcke zu kontrollieren.',0), -14002 => array('PiePlot3D::SetAngle() 3D-Torten-Projektionswinkel muss zwischen 5 und 85 Grad sein.',0), -14003 => array('Interne Festlegung schlug fehl. Pie3D::Pie3DSlice',0), -14004 => array('TortenstÃŒck-Startwinkel muss zwischen 0 und 360 Grad sein.',0), -14005 => array('Pie3D Interner Fehler: Versuch, zweimal zu umhÃŒllen bei der Suche nach dem Startindex.',0,), -14006 => array('Pie3D Interner Fehler: Z-Sortier-Algorithmus fÃŒr 3D-Tortendiagramme funktioniert nicht einwandfrei (2). Versuch, zweimal zu umhÃŒllen beim Erstellen des Bildes.',0), -14007 => array('Die Breite fÃŒr das 3D-Tortendiagramm ist 0. Gib eine Breite > 0 an.',0), - -/* -** jpgraph_pie -*/ - -15001 => array('PiePLot::SetTheme() Unbekannter Stil: %s',1), -15002 => array('Argument fÃŒr PiePlot::ExplodeSlice() muss ein Integer-Wert sein',0), -15003 => array('Argument fÃŒr PiePlot::Explode() muss ein Vektor mit Integer-Werten sein.',0), -15004 => array('TortenstÃŒck-Startwinkel muss zwischen 0 und 360 Grad sein.',0), -15005 => array('PiePlot::SetFont() sollte nicht mehr verwendet werden. Benutze stattdessen PiePlot->value->SetFont().',0), -15006 => array('PiePlot::SetSize() Radius fÃŒr Tortendiagramm muss entweder als Bruch [0, 0.5] der Bildgröße oder als Absoluwert in Pixel im Bereich [10, 1000] angegeben werden.',0), -15007 => array('PiePlot::SetFontColor() sollte nicht mehr verwendet werden. Benutze stattdessen PiePlot->value->SetColor()..',0), -15008 => array('PiePlot::SetLabelType() der Typ fÃŒr Tortendiagramme muss entweder 0 or 1 sein (nicht %d).',1), -15009 => array('UngÃŒltiges Tortendiagramm. Die Summe aller Daten ist Null.',0), -15010 => array('Die Summe aller Daten ist Null.',0), -15011 => array('Um Bildtransformationen benutzen zu können, muss die Datei jpgraph_imgtrans.php eingefÃŒgt werden (per include).',0), - -/* -** jpgraph_plotband -*/ - -16001 => array('Die Dichte fÃŒr das Pattern muss zwischen 1 und 100 sein. (Du hast %f eingegeben)',1), -16002 => array('Es wurde keine Position fÃŒr das Pattern angegeben.',0), -16003 => array('Unbekannte Pattern-Definition (%d)',0), -16004 => array('Der Mindeswert fÃŒr das PlotBand ist größer als der Maximalwert. Bitte korrigiere dies!',0), - - -/* -** jpgraph_polar -*/ - -17001 => array('PolarPlots mÃŒssen eine gerade Anzahl von Datenpunkten haben. Jeder Datenpunkt ist ein Tupel (Winkel, Radius).',0), -17002 => array('Unbekannte Ausrichtung fÃŒr X-Achsen-Titel. (%s)',1), -//17003 => array('Set90AndMargin() wird fÃŒr PolarGraph nicht unterstÃŒtzt.',0), -17004 => array('Unbekannter Achsentyp fÃŒr PolarGraph. Er muss entweder \'lin\' oder \'log\' sein.',0), - -/* -** jpgraph_radar -*/ - -18001 => array('ClientSideImageMaps werden fÃŒr RadarPlots nicht unterstÃŒtzt.',0), -18002 => array('RadarGraph::SupressTickMarks() sollte nicht mehr verwendet werden. Benutze stattdessen HideTickMarks().',0), -18003 => array('UngÃŒltiger Achsentyp fÃŒr RadarPlot (%s). Er muss entweder \'lin\' oder \'log\' sein.',1), -18004 => array('Die RadarPlot-Größe muss zwischen 0.1 und 1 sein. (Dein Wert=%f)',1), -18005 => array('RadarPlot: nicht unterstÃŒtzte Tick-Dichte: %d',1), -18006 => array('Minimum Daten %f (RadarPlots sollten nur verwendet werden, wenn alle Datenpunkte einen Wert > 0 haben).',1), -18007 => array('Die Anzahl der Titel entspricht nicht der Anzahl der Datenpunkte.',0), -18008 => array('Jeder RadarPlot muss die gleiche Anzahl von Datenpunkten haben.',0), - -/* -** jpgraph_regstat -*/ - -19001 => array('Spline: Anzahl der X- und Y-Koordinaten muss gleich sein.',0), -19002 => array('UngÃŒltige Dateneingabe fÃŒr Spline. Zwei oder mehr aufeinanderfolgende X-Werte sind identisch. Jeder eigegebene X-Wert muss unterschiedlich sein, weil vom mathematischen Standpunkt ein Eins-zu-Eins-Mapping vorliegen muss, d.h. jeder X-Wert korrespondiert mit exakt einem Y-Wert.',0), -19003 => array('Bezier: Anzahl der X- und Y-Koordinaten muss gleich sein.',0), - -/* -** jpgraph_scatter -*/ - -20001 => array('Fieldplots mÃŒssen die gleiche Anzahl von X und Y Datenpunkten haben.',0), -20002 => array('Bei Fieldplots muss ein Winkel fÃŒr jeden X und Y Datenpunkt angegeben werden.',0), -20003 => array('Scatterplots mÃŒssen die gleiche Anzahl von X- und Y-Datenpunkten haben.',0), - -/* -** jpgraph_stock -*/ - -21001 => array('Die Anzahl der Datenwerte fÃŒr Stock-Charts mÃŒssen ein Mehrfaches von %d Datenpunkten sein.',1), - -/* -** jpgraph_plotmark -*/ - -23001 => array('Der Marker "%s" existiert nicht in der Farbe: %d',2), -23002 => array('Der Farb-Index ist zu hoch fÃŒr den Marker "%s"',1), -23003 => array('Ein Dateiname muss angegeben werden, wenn Du den Marker-Typ auf MARK_IMG setzt.',0), - -/* -** jpgraph_utils -*/ - -24001 => array('FuncGenerator : Keine Funktion definiert. ',0), -24002 => array('FuncGenerator : Syntax-Fehler in der Funktionsdefinition ',0), -24003 => array('DateScaleUtils: Unknown tick type specified in call to GetTicks()',0), -24004 => array('ReadCSV2: Die anzahl der spalten fehler in %s reihe %d',2), -/* -** jpgraph -*/ - -25001 => array('Diese PHP-Installation ist nicht mit der GD-Bibliothek kompiliert. Bitte kompiliere PHP mit GD-UnterstÃŒtzung neu, damit JpGraph funktioniert. (Weder die Funktion imagetypes() noch imagecreatefromstring() existiert!)',0), -25002 => array('Diese PHP-Installation scheint nicht die benötigte GD-Bibliothek zu unterstÃŒtzen. Bitte schau in der PHP-Dokumentation nach, wie man die GD-Bibliothek installiert und aktiviert.',0), -25003 => array('Genereller PHP Fehler : Bei %s:%d : %s',3), -25004 => array('Genereller PHP Fehler : %s ',1), -25005 => array('PHP_SELF, die PHP-Global-Variable kann nicht ermittelt werden. PHP kann nicht von der Kommandozeile gestartet werden, wenn der Cache oder die Bilddateien automatisch benannt werden sollen.',0), -25006 => array('Die Benutzung der FF_CHINESE (FF_BIG5) Schriftfamilie benötigt die iconv() Funktion in Deiner PHP-Konfiguration. Dies wird nicht defaultmÀßig in PHP kompiliert (benötigt "--width-iconv" bei der Konfiguration).',0), -25007 => array('Du versuchst das lokale (%s) zu verwenden, was von Deiner PHP-Installation nicht unterstÃŒtzt wird. Hinweis: Benutze \'\', um das defaultmÀßige Lokale fÃŒr diese geographische Region festzulegen.',1), -25008 => array('Die Bild-Breite und Höhe in Graph::Graph() mÃŒssen numerisch sein',0), -25009 => array('Die Skalierung der Achsen muss angegeben werden mit Graph::SetScale()',0), - -25010 => array('Graph::Add() Du hast versucht, einen leeren Plot zum Graph hinzuzufÃŒgen.',0), -25011 => array('Graph::AddY2() Du hast versucht, einen leeren Plot zum Graph hinzuzufÃŒgen.',0), -25012 => array('Graph::AddYN() Du hast versucht, einen leeren Plot zum Graph hinzuzufÃŒgen.',0), -25013 => array('Es können nur Standard-Plots zu multiplen Y-Achsen hinzugefÃŒgt werden',0), -25014 => array('Graph::AddText() Du hast versucht, einen leeren Text zum Graph hinzuzufÃŒgen.',0), -25015 => array('Graph::AddLine() Du hast versucht, eine leere Linie zum Graph hinzuzufÃŒgen.',0), -25016 => array('Graph::AddBand() Du hast versucht, ein leeres Band zum Graph hinzuzufÃŒgen.',0), -25017 => array('Du benutzt GD 2.x und versuchst, ein Hintergrundbild in einem Truecolor-Bild zu verwenden. Um Hintergrundbilder mit GD 2.x zu verwenden, ist es notwendig, Truecolor zu aktivieren, indem die USE_TRUECOLOR-Konstante auf TRUE gesetzt wird. Wegen eines Bugs in GD 2.0.1 ist die QualitÀt der Schrift sehr schlecht, wenn Truetype-Schrift in Truecolor-Bildern verwendet werden.',0), -25018 => array('Falscher Dateiname fÃŒr Graph::SetBackgroundImage() : "%s" muss eine gÃŒltige Dateinamenerweiterung (jpg,gif,png) haben, wenn die automatische Dateityperkennung verwenndet werden soll.',1), -25019 => array('Unbekannte Dateinamenerweiterung (%s) in Graph::SetBackgroundImage() fÃŒr Dateiname: "%s"',2), - -25020 => array('Graph::SetScale(): Dar Maximalwert muss größer sein als der Mindestwert.',0), -25021 => array('Unbekannte Achsendefinition fÃŒr die Y-Achse. (%s)',1), -25022 => array('Unbekannte Achsendefinition fÃŒr die X-Achse. (%s)',1), -25023 => array('Nicht unterstÃŒtzter Y2-Achsentyp: "%s" muss einer von (lin,log,int) sein.',1), -25024 => array('Nicht unterstÃŒtzter X-Achsentyp: "%s" muss einer von (lin,log,int) sein.',1), -25025 => array('Nicht unterstÃŒtzte Tick-Dichte: %d',1), -25026 => array('Nicht unterstÃŒtzter Typ der nicht angegebenen Y-Achse. Du hast entweder: 1. einen Y-Achsentyp fÃŒr automatisches Skalieren definiert, aber keine Plots angegeben. 2. eine Achse direkt definiert, aber vergessen, die Tick-Dichte zu festzulegen.',0), -25027 => array('Kann cached CSIM "%s" zum Lesen nicht öffnen.',1), -25028 => array('Apache/PHP hat keine Schreibrechte, in das CSIM-Cache-Verzeichnis (%s) zu schreiben. ÜberprÃŒfe die Rechte.',1), -25029 => array('Kann nicht in das CSIM "%s" schreiben. ÜberprÃŒfe die Schreibrechte und den freien Speicherplatz.',1), - -25030 => array('Fehlender Skriptname fÃŒr StrokeCSIM(). Der Name des aktuellen Skriptes muss als erster Parameter von StrokeCSIM() angegeben werden.',0), -25031 => array('Der Achsentyp muss mittels Graph::SetScale() angegeben werden.',0), -25032 => array('Es existieren keine Plots fÃŒr die Y-Achse nbr:%d',1), -25033 => array('',0), -25034 => array('Undefinierte X-Achse kann nicht gezeichnet werden. Es wurden keine Plots definiert.',0), -25035 => array('Du hast Clipping aktiviert. Clipping wird nur fÃŒr Diagramme mit 0 oder 90 Grad Rotation unterstÃŒtzt. Bitte verÀndere Deinen Rotationswinkel (=%d Grad) dementsprechend oder deaktiviere Clipping.',1), -25036 => array('Unbekannter Achsentyp AxisStyle() : %s',1), -25037 => array('Das Bildformat Deines Hintergrundbildes (%s) wird von Deiner System-Konfiguration nicht unterstÃŒtzt. ',1), -25038 => array('Das Hintergrundbild scheint von einem anderen Typ (unterschiedliche Dateierweiterung) zu sein als der angegebene Typ. Angegebenen: %s; Datei: %s',2), -25039 => array('Hintergrundbild kann nicht gelesen werden: "%s"',1), - -25040 => array('Es ist nicht möglich, sowohl ein Hintergrundbild als auch eine Hintergrund-Landesflagge anzugeben.',0), -25041 => array('Um Landesflaggen als Hintergrund benutzen zu können, muss die Datei "jpgraph_flags.php" eingefÃŒgt werden (per include).',0), -25042 => array('Unbekanntes Hintergrundbild-Layout',0), -25043 => array('Unbekannter Titelhintergrund-Stil.',0), -25044 => array('Automatisches Skalieren kann nicht verwendet werden, weil es unmöglich ist, einen gÃŒltigen min/max Wert fÃŒr die Y-Achse zu ermitteln (nur Null-Werte).',0), -25045 => array('Die Schriftfamilien FF_HANDWRT und FF_BOOK sind wegen Copyright-Problemen nicht mehr verfÃŒgbar. Diese Schriften können nicht mehr mit JpGraph verteilt werden. Bitte lade Dir Schriften von http://corefonts.sourceforge.net/ herunter.',0), -25046 => array('Angegebene TTF-Schriftfamilie (id=%d) ist unbekannt oder existiert nicht. Bitte merke Dir, dass TTF-Schriften wegen Copyright-Problemen nicht mit JpGraph mitgeliefert werden. Du findest MS-TTF-Internetschriften (arial, courier, etc.) zum Herunterladen unter http://corefonts.sourceforge.net/',1), -25047 => array('Stil %s ist nicht verfÃŒgbar fÃŒr Schriftfamilie %s',2), -25048 => array('Unbekannte Schriftstildefinition [%s].',1), -25049 => array('Schriftdatei "%s" ist nicht lesbar oder existiert nicht.',1), - -25050 => array('Erstes Argument fÃŒr Text::Text() muss ein String sein.',0), -25051 => array('UngÃŒltige Richtung angegeben fÃŒr Text.',0), -25052 => array('PANIK: Interner Fehler in SuperScript::Stroke(). Unbekannte vertikale Ausrichtung fÃŒr Text.',0), -25053 => array('PANIK: Interner Fehler in SuperScript::Stroke(). Unbekannte horizontale Ausrichtung fÃŒr Text.',0), -25054 => array('Interner Fehler: Unbekannte Grid-Achse %s',1), -25055 => array('Axis::SetTickDirection() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetTickSide().',0), -25056 => array('SetTickLabelMargin() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetLabelMargin().',0), -25057 => array('SetTextTicks() sollte nicht mehr verwendet werden. Benutze stattdessen SetTextTickInterval().',0), -25058 => array('TextLabelIntevall >= 1 muss angegeben werden.',0), -25059 => array('SetLabelPos() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetLabelSide().',0), - -25060 => array('Unbekannte Ausrichtung angegeben fÃŒr X-Achsentitel (%s).',1), -25061 => array('Unbekannte Ausrichtung angegeben fÃŒr Y-Achsentitel (%s).',1), -25062 => array('Label unter einem Winkel werden fÃŒr die Y-Achse nicht unterstÃŒtzt.',0), -25063 => array('Ticks::SetPrecision() sollte nicht mehr verwendet werden. Benutze stattdessen Ticks::SetLabelFormat() (oder Ticks::SetFormatCallback()).',0), -25064 => array('Kleinere oder größere Schrittgröße ist 0. ÜberprÃŒfe, ob Du fÀlschlicherweise SetTextTicks(0) in Deinem Skript hast. Wenn dies nicht der Fall ist, bist Du eventuell ÃŒber einen Bug in JpGraph gestolpert. Bitte sende einen Report und fÃŒge den Code an, der den Fehler verursacht hat.',0), -25065 => array('Tick-Positionen mÃŒssen als array() angegeben werden',0), -25066 => array('Wenn die Tick-Positionen und -Label von Hand eingegeben werden, muss die Anzahl der Ticks und der Label gleich sein.',0), -25067 => array('Deine von Hand eingegebene Achse und Ticks sind nicht korrekt. Die Skala scheint zu klein zu sein fÃŒr den Tickabstand.',0), -25068 => array('Ein Plot hat eine ungÃŒltige Achse. Dies kann beispielsweise der Fall sein, wenn Du automatisches Text-Skalieren verwendest, um ein Liniendiagramm zu zeichnen mit nur einem Datenpunkt, oder wenn die BildflÀche zu klein ist. Es kann auch der Fall sein, dass kein Datenpunkt einen numerischen Wert hat (vielleicht nur \'-\' oder \'x\').',0), -25069 => array('Grace muss größer sein als 0',0), - -25070 => array('Deine Daten enthalten nicht-numerische Werte.',0), -25071 => array('Du hast mit SetAutoMin() einen Mindestwert angegeben, der größer ist als der Maximalwert fÃŒr die Achse. Dies ist nicht möglich.',0), -25072 => array('Du hast mit SetAutoMax() einen Maximalwert angegeben, der kleiner ist als der Minimalwert der Achse. Dies ist nicht möglich.',0), -25073 => array('Interner Fehler. Der Integer-Skalierungs-Algorithmus-Vergleich ist außerhalb der Grenzen (r=%f).',1), -25074 => array('Interner Fehler. Der Skalierungsbereich ist negativ (%f) [fÃŒr %s Achse]. Dieses Problem könnte verursacht werden durch den Versuch, \'ungÃŒltige\' Werte in die Daten-Vektoren einzugeben (z.B. nur String- oder NULL-Werte), was beim automatischen Skalieren einen Fehler erzeugt.',2), -25075 => array('Die automatischen Ticks können nicht gesetzt werden, weil min==max.',0), -25077 => array('Einstellfaktor fÃŒr die Farbe muss größer sein als 0',0), -25078 => array('Unbekannte Farbe: %s',1), -25079 => array('Unbekannte Farbdefinition: %s, Größe=%d',2), - -25080 => array('Der Alpha-Parameter fÃŒr Farben muss zwischen 0.0 und 1.0 liegen.',0), -25081 => array('Das ausgewÀhlte Grafikformat wird entweder nicht unterstÃŒtzt oder ist unbekannt [%s]',1), -25082 => array('Es wurden ungÃŒltige Größen fÃŒr Breite und Höhe beim Erstellen des Bildes definiert (Breite=%d, Höhe=%d).',2), -25083 => array('Es wurde eine ungÃŒltige Größe beim Kopieren des Bildes angegeben. Die Größe fÃŒr das kopierte Bild wurde auf 1 Pixel oder weniger gesetzt.',0), -25084 => array('Fehler beim Erstellen eines temporÀren GD-Canvas. Möglicherweise liegt ein Arbeitsspeicherproblem vor.',0), -25085 => array('Ein Bild kann nicht aus dem angegebenen String erzeugt werden. Er ist entweder in einem nicht unterstÃŒtzen Format oder er represÀntiert ein kaputtes Bild.',0), -25086 => array('Du scheinst nur GD 1.x installiert zu haben. Um Alphablending zu aktivieren, ist GD 2.x oder höher notwendig. Bitte installiere GD 2.x oder versichere Dich, dass die Konstante USE_GD2 richtig gesetzt ist. StandardmÀßig wird die installierte GD-Version automatisch erkannt. Ganz selten wird GD2 erkannt, obwohl nur GD1 installiert ist. Die Konstante USE_GD2 muss dann zu "false" gesetzt werden.',0), -25087 => array('Diese PHP-Version wurde ohne TTF-UnterstÃŒtzung konfiguriert. PHP muss mit TTF-UnterstÃŒtzung neu kompiliert und installiert werden.',0), -25088 => array('Die GD-SchriftunterstÃŒtzung wurde falsch konfiguriert. Der Aufruf von imagefontwidth() ist fehlerhaft.',0), -25089 => array('Die GD-SchriftunterstÃŒtzung wurde falsch konfiguriert. Der Aufruf von imagefontheight() ist fehlerhaft.',0), - -25090 => array('Unbekannte Richtung angegeben im Aufruf von StrokeBoxedText() [%s].',1), -25091 => array('Die interne Schrift untestÃŒtzt das Schreiben von Text in einem beliebigen Winkel nicht. Benutze stattdessen TTF-Schriften.',0), -25092 => array('Es liegt entweder ein Konfigurationsproblem mit TrueType oder ein Problem beim Lesen der Schriftdatei "%s" vor. Versichere Dich, dass die Datei existiert und Leserechte und -pfad vergeben sind. (wenn \'basedir\' restriction in PHP aktiviert ist, muss die Schriftdatei im Dokumentwurzelverzeichnis abgelegt werden). Möglicherweise ist die FreeType-Bibliothek falsch installiert. Versuche, mindestens zur FreeType-Version 2.1.13 zu aktualisieren und kompiliere GD mit einem korrekten Setup neu, damit die FreeType-Bibliothek gefunden werden kann.',1), -25093 => array('Die Schriftdatei "%s" kann nicht gelesen werden beim Aufruf von Image::GetBBoxTTF. Bitte versichere Dich, dass die Schrift gesetzt wurde, bevor diese Methode aufgerufen wird, und dass die Schrift im TTF-Verzeichnis installiert ist.',1), -25094 => array('Die Textrichtung muss in einem Winkel zwischen 0 und 90 engegeben werden.',0), -25095 => array('Unbekannte Schriftfamilien-Definition. ',0), -25096 => array('Der Farbpalette können keine weiteren Farben zugewiesen werden. Dem Bild wurde bereits die größtmögliche Anzahl von Farben (%d) zugewiesen und die Palette ist voll. Verwende stattdessen ein TrueColor-Bild',0), -25097 => array('Eine Farbe wurde als leerer String im Aufruf von PushColor() angegegeben.',0), -25098 => array('Negativer Farbindex. Unpassender Aufruf von PopColor().',0), -25099 => array('Die Parameter fÃŒr Helligkeit und Kontrast sind außerhalb des zulÀssigen Bereichs [-1,1]',0), - -25100 => array('Es liegt ein Problem mit der Farbpalette und dem GD-Setup vor. Bitte deaktiviere anti-aliasing oder verwende GD2 mit TrueColor. Wenn die GD2-Bibliothek installiert ist, versichere Dich, dass die Konstante USE_GD2 auf "true" gesetzt und TrueColor aktiviert ist.',0), -25101 => array('UngÃŒltiges numerisches Argument fÃŒr SetLineStyle(): (%d)',1), -25102 => array('UngÃŒltiges String-Argument fÃŒr SetLineStyle(): %s',1), -25103 => array('UngÃŒltiges Argument fÃŒr SetLineStyle %s',1), -25104 => array('Unbekannter Linientyp: %s',1), -25105 => array('Es wurden NULL-Daten fÃŒr ein gefÃŒlltes Polygon angegeben. Sorge dafÃŒr, dass keine NULL-Daten angegeben werden.',0), -25106 => array('Image::FillToBorder : es können keine weiteren Farben zugewiesen werden.',0), -25107 => array('In Datei "%s" kann nicht geschrieben werden. ÜberprÃŒfe die aktuellen Schreibrechte.',1), -25108 => array('Das Bild kann nicht gestreamt werden. Möglicherweise liegt ein Fehler im PHP/GD-Setup vor. Kompiliere PHP neu und verwende die eingebaute GD-Bibliothek, die mit PHP angeboten wird.',0), -25109 => array('Deine PHP- (und GD-lib-) Installation scheint keine bekannten Grafikformate zu unterstÃŒtzen. Sorge zunÀchst dafÃŒr, dass GD als PHP-Modul kompiliert ist. Wenn Du außerdem JPEG-Bilder verwenden willst, musst Du die JPEG-Bibliothek installieren. Weitere Details sind in der PHP-Dokumentation zu finden.',0), - -25110 => array('Dein PHP-Installation unterstÃŒtzt das gewÀhlte Grafikformat nicht: %s',1), -25111 => array('Das gecachete Bild %s kann nicht gelöscht werden. Problem mit den Rechten?',1), -25112 => array('Das Datum der gecacheten Datei (%s) liegt in der Zukunft.',1), -25113 => array('Das gecachete Bild %s kann nicht gelöscht werden. Problem mit den Rechten?',1), -25114 => array('PHP hat nicht die erforderlichen Rechte, um in die Cache-Datei %s zu schreiben. Bitte versichere Dich, dass der Benutzer, der PHP anwendet, die entsprechenden Schreibrechte fÃŒr die Datei hat, wenn Du das Cache-System in JPGraph verwenden willst.',1), -25115 => array('Berechtigung fÃŒr gecachetes Bild %s kann nicht gesetzt werden. Problem mit den Rechten?',1), -25116 => array('Datei kann nicht aus dem Cache %s geöffnet werden',1), -25117 => array('Gecachetes Bild %s kann nicht zum Lesen geöffnet werden.',1), -25118 => array('Verzeichnis %s kann nicht angelegt werden. Versichere Dich, dass PHP die Schreibrechte in diesem Verzeichnis hat.',1), -25119 => array('Rechte fÃŒr Datei %s können nicht gesetzt werden. Problem mit den Rechten?',1), - -25120 => array('Die Position fÃŒr die Legende muss als Prozentwert im Bereich 0-1 angegeben werden.',0), -25121 => array('Eine leerer Datenvektor wurde fÃŒr den Plot eingegeben. Es muss wenigstens ein Datenpunkt vorliegen.',0), -25122 => array('Stroke() muss als Subklasse der Klasse Plot definiert sein.',0), -25123 => array('Du kannst keine Text-X-Achse mit X-Koordinaten verwenden. Benutze stattdessen eine "int" oder "lin" Achse.',0), -25124 => array('Der Eingabedatenvektor mus aufeinanderfolgende Werte von 0 aufwÀrts beinhalten. Der angegebene Y-Vektor beginnt mit leeren Werten (NULL).',0), -25125 => array('UngÃŒltige Richtung fÃŒr statische Linie.',0), -25126 => array('Es kann kein TrueColor-Bild erzeugt werden. ÜberprÃŒfe, ob die GD2-Bibliothek und PHP korrekt aufgesetzt wurden.',0), -25127 => array('The library has been configured for automatic encoding conversion of Japanese fonts. This requires that PHP has the mb_convert_encoding() function. Your PHP installation lacks this function (PHP needs the "--enable-mbstring" when compiled).',0), -25128 => array('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.',0), -25129 => array('Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines.',0), -25130 => array('Too small plot area. (%d x %d). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.',2), - -25131 => array('StrokeBoxedText2() only supports TTF fonts and not built-in bitmap fonts.',0), - -/* -** jpgraph_led -*/ - -25500 => array('Multibyte strings must be enabled in the PHP installation in order to run the LED module so that the function mb_strlen() is available. See PHP documentation for more information.',0), - - -/* -**--------------------------------------------------------------------------------------------- -** Pro-version strings -**--------------------------------------------------------------------------------------------- -*/ - -/* -** jpgraph_table -*/ - -27001 => array('GTextTable: UngÃŒltiges Argument fÃŒr Set(). Das Array-Argument muss 2-- dimensional sein.',0), -27002 => array('GTextTable: UngÃŒltiges Argument fÃŒr Set()',0), -27003 => array('GTextTable: Falsche Anzahl von Argumenten fÃŒr GTextTable::SetColor()',0), -27004 => array('GTextTable: Angegebener Zellenbereich, der verschmolzen werden soll, ist ungÃŒltig.',0), -27005 => array('GTextTable: Bereits verschmolzene Zellen im Bereich (%d,%d) bis (%d,%d) können nicht ein weiteres Mal verschmolzen werden.',4), -27006 => array('GTextTable: Spalten-Argument = %d liegt außerhalb der festgelegten Tabellengröße.',1), -27007 => array('GTextTable: Zeilen-Argument = %d liegt außerhalb der festgelegten Tabellengröße.',1), -27008 => array('GTextTable: Spalten- und Zeilengröße mÃŒssen zu den Dimensionen der Tabelle passen.',0), -27009 => array('GTextTable: Die Anzahl der Tabellenspalten oder -zeilen ist 0. Versichere Dich, dass die Methoden Init() oder Set() aufgerufen werden.',0), -27010 => array('GTextTable: Es wurde keine Ausrichtung beim Aufruf von SetAlign() angegeben.',0), -27011 => array('GTextTable: Es wurde eine unbekannte Ausrichtung beim Aufruf von SetAlign() abgegeben. Horizontal=%s, Vertikal=%s',2), -27012 => array('GTextTable: Interner Fehler. Es wurde ein ungÃŒltiges Argument festgeleget %s',1), -27013 => array('GTextTable: Das Argument fÃŒr FormatNumber() muss ein String sein.',0), -27014 => array('GTextTable: Die Tabelle wurde weder mit einem Aufruf von Set() noch von Init() initialisiert.',0), -27015 => array('GTextTable: Der Zellenbildbedingungstyp muss entweder TIMG_WIDTH oder TIMG_HEIGHT sein.',0), - -/* -** jpgraph_windrose -*/ - -22001 => array('Die Gesamtsumme der prozentualen Anteile aller Windrosenarme darf 100%% nicht ÃŒberschreiten!\n(Aktuell max: %d)',1), -22002 => array('Das Bild ist zu klein fÃŒr eine Skala. Bitte vergrößere das Bild.',0), -22004 => array('Die Etikettendefinition fÃŒr Windrosenrichtungen mÃŒssen 16 Werte haben (eine fÃŒr jede Kompassrichtung).',0), -22005 => array('Der Linientyp fÃŒr radiale Linien muss einer von ("solid","dotted","dashed","longdashed") sein.',0), -22006 => array('Es wurde ein ungÃŒltiger Windrosentyp angegeben.',0), -22007 => array('Es wurden zu wenig Werte fÃŒr die Bereichslegende angegeben.',0), -22008 => array('Interner Fehler: Versuch, eine freie Windrose zu plotten, obwohl der Typ keine freie Windrose ist.',0), -22009 => array('Du hast die gleiche Richtung zweimal angegeben, einmal mit einem Winkel und einmal mit einer Kompassrichtung (%f Grad).',0), -22010 => array('Die Richtung muss entweder ein numerischer Wert sein oder eine der 16 Kompassrichtungen',0), -22011 => array('Der Windrosenindex muss ein numerischer oder Richtungswert sein. Du hast angegeben Index=%d',1), -22012 => array('Die radiale Achsendefinition fÃŒr die Windrose enthÀlt eine nicht aktivierte Richtung.',0), -22013 => array('Du hast dasselbe Look&Feel fÃŒr die gleiche Kompassrichtung zweimal engegeben, einmal mit Text und einmal mit einem Index (Index=%d)',1), -22014 => array('Der Index fÃŒr eine Kompassrichtung muss zwischen 0 und 15 sein.',0), -22015 => array('Du hast einen unbekannten Windrosenplottyp angegeben.',0), -22016 => array('Der Windrosenarmindex muss ein numerischer oder ein Richtungswert sein.',0), -22017 => array('Die Windrosendaten enthalten eine Richtung, die nicht aktiviert ist. Bitte berichtige, welche Label angezeigt werden sollen.',0), -22018 => array('Du hast fÃŒr dieselbe Kompassrichtung zweimal Daten angegeben, einmal mit Text und einmal mit einem Index (Index=%d)',1), -22019 => array('Der Index fÃŒr eine Richtung muss zwischen 0 und 15 sein. Winkel dÃŒrfen nicht fÃŒr einen regelmÀßigen Windplot angegeben werden, sondern entweder ein Index oder eine Kompassrichtung.',0), -22020 => array('Der Windrosenplot ist zu groß fÃŒr die angegebene Bildgröße. Benutze entweder WindrosePlot::SetSize(), um den Plot kleiner zu machen oder vergrößere das Bild im ursprÃŒnglichen Aufruf von WindroseGraph().',0), -22021 => array('It is only possible to add Text, IconPlot or WindrosePlot to a Windrose Graph',0), - -/* -** jpgraph_odometer -*/ - -13001 => array('Unbekannter Nadeltypstil (%d).',1), -13002 => array('Ein Wert fÃŒr das Odometer (%f) ist außerhalb des angegebenen Bereichs [%f,%f]',3), - -/* -** jpgraph_barcode -*/ - -1001 => array('Unbekannte Kodier-Specifikation: %s',1), -1002 => array('datenvalidierung schlug fehl. [%s] kann nicht mittels der Kodierung "%s" kodiert werden',2), -1003 => array('Interner Kodierfehler. Kodieren von %s ist nicht möglich in Code 128',1), -1004 => array('Interner barcode Fehler. Unbekannter UPC-E Kodiertyp: %s',1), -1005 => array('Interner Fehler. Das Textzeichen-Tupel (%s, %s) kann nicht im Code-128 Zeichensatz C kodiert werden.',2), -1006 => array('Interner Kodierfehler fÃŒr CODE 128. Es wurde versucht, CTRL in CHARSET != A zu kodieren.',0), -1007 => array('Interner Kodierfehler fÃŒr CODE 128. Es wurde versucht, DEL in CHARSET != B zu kodieren.',0), -1008 => array('Interner Kodierfehler fÃŒr CODE 128. Es wurde versucht, kleine Buchstaben in CHARSET != B zu kodieren.',0), -1009 => array('Kodieren mittels CODE 93 wird noch nicht unterstÃŒtzt.',0), -1010 => array('Kodieren mittels POSTNET wird noch nicht unterstÃŒtzt.',0), -1011 => array('Nicht untrstÃŒtztes Barcode-Backend fÃŒr den Typ %s',1), - -/* -** PDF417 -*/ - -26000 => array('PDF417: The PDF417 module requires that the PHP installation must support the function bcmod(). This is normally enabled at compile time. See documentation for more information.',0), -26001 => array('PDF417: Die Anzahl der Spalten muss zwischen 1 und 30 sein.',0), -26002 => array('PDF417: Der Fehler-Level muss zwischen 0 und 8 sein.',0), -26003 => array('PDF417: UngÃŒltiges Format fÃŒr Eingabedaten, um sie mit PDF417 zu kodieren.',0), -26004 => array('PDF417: die eigebenen Daten können nicht mit Fehler-Level %d und %d spalten kodiert werden, weil daraus zu viele Symbole oder mehr als 90 Zeilen resultieren.',2), -26005 => array('PDF417: Die Datei "%s" kann nicht zum Schreiben geöffnet werden.',1), -26006 => array('PDF417: Interner Fehler. Die Eingabedatendatei fÃŒr PDF417-Cluster %d ist fehlerhaft.',1), -26007 => array('PDF417: Interner Fehler. GetPattern: UngÃŒltiger Code-Wert %d (Zeile %d)',2), -26008 => array('PDF417: Interner Fehler. Modus wurde nicht in der Modusliste!! Modus %d',1), -26009 => array('PDF417: Kodierfehler: UngÃŒltiges Zeichen. Zeichen kann nicht mit ASCII-Code %d kodiert werden.',1), -26010 => array('PDF417: Interner Fehler: Keine Eingabedaten beim Dekodieren.',0), -26011 => array('PDF417: Kodierfehler. Numerisches Kodieren bei nicht-numerischen Daten nicht möglich.',0), -26012 => array('PDF417: Interner Fehler. Es wurden fÃŒr den Binary-Kompressor keine Daten zum Dekodieren eingegeben.',0), -26013 => array('PDF417: Interner Fehler. Checksum Fehler. Koeffiziententabellen sind fehlerhaft.',0), -26014 => array('PDF417: Interner Fehler. Es wurden keine Daten zum Berechnen von Kodewörtern eingegeben.',0), -26015 => array('PDF417: Interner Fehler. Ein Eintrag 0 in die StatusÃŒbertragungstabellen ist nicht NULL. Eintrag 1 = (%s)',1), -26016 => array('PDF417: Interner Fehler: Nichtregistrierter StatusÃŒbertragungsmodus beim Dekodieren.',0), - - -/* -** jpgraph_contour -*/ - -28001 => array('Dritten parameter fur Contour muss ein vector der fargen sind.',0), -28002 => array('Die anzahlen der farges jeder isobar linien muss gleich sein.',0), -28003 => array('ContourPlot Interner Fehler: isobarHCrossing: Spalten index ist zu hoch (%d)',1), -28004 => array('ContourPlot Interner Fehler: isobarHCrossing: Reihe index ist zu hoch (%d)',1), -28005 => array('ContourPlot Interner Fehler: isobarVCrossing: Reihe index ist zu hoch (%d)',1), -28006 => array('ContourPlot Interner Fehler: isobarVCrossing: Spalten index ist zu hoch (%d)',1), -28007 => array('ContourPlot. Interpolation faktor ist zu hoch (>5)',0), - - -/* - * jpgraph_matrix and colormap -*/ -29201 => array('Min range value must be less or equal to max range value for colormaps',0), -29202 => array('The distance between min and max value is too small for numerical precision',0), -29203 => array('Number of color quantification level must be at least %d',1), -29204 => array('Number of colors (%d) is invalid for this colormap. It must be a number that can be written as: %d + k*%d',3), -29205 => array('Colormap specification out of range. Must be an integer in range [0,%d]',1), -29206 => array('Invalid object added to MatrixGraph',0), -29207 => array('Empty input data specified for MatrixPlot',0), -29208 => array('Unknown side specifiction for matrix labels "%s"',1), -29209 => array('CSIM Target matrix must be the same size as the data matrix (csim=%d x %d, data=%d x %d)',4), -29210 => array('CSIM Target for matrix labels does not match the number of labels (csim=%d, labels=%d)',2), - -); - -?> +,) +$_jpg_messages = array( + +/* +** Headers wurden bereits gesendet - Fehler. Dies wird als HTML formatiert, weil es direkt als text zurueckgesendet wird +*/ +10 => array('
      JpGraph Fehler: +HTTP header wurden bereits gesendet.
      Fehler in der Datei %s in der Zeile %d.
      ErklÀrung:
      HTTP header wurden bereits zum Browser gesendet, wobei die Daten als Text gekennzeichnet wurden, bevor die Bibliothek die Chance hatte, seinen Bild-HTTP-Header zum Browser zu schicken. Dies verhindert, dass die Bibliothek Bilddaten zum Browser schicken kann (weil sie vom Browser als Text interpretiert wÃŒrden und daher nur Mist dargestellt wÃŒrde).

      Wahrscheinlich steht Text im Skript bevor Graph::Stroke() aufgerufen wird. Wenn dieser Text zum Browser gesendet wird, nimmt dieser an, dass die gesamten Daten aus Text bestehen. Such nach irgendwelchem Text, auch nach Leerzeichen und ZeilenumbrÃŒchen, die eventuell bereits zum Browser gesendet wurden.

      Zum Beispiel ist ein oft auftretender Fehler, eine Leerzeile am Anfang der Datei oder vor Graph::Stroke() zu lassen."<?php".

      ',2), + +/* +** Setup Fehler +*/ +11 => array('Es wurde kein Pfad fÃŒr CACHE_DIR angegeben. Bitte gib einen Pfad CACHE_DIR in der Datei jpg-config.inc an.',0), +12 => array('Es wurde kein Pfad fÃŒr TTF_DIR angegeben und der Pfad kann nicht automatisch ermittelt werden. Bitte gib den Pfad in der Datei jpg-config.inc an.',0), +13 => array('The installed PHP version (%s) is not compatible with this release of the library. The library requires at least PHP version %s',2), + +/* +** jpgraph_bar +*/ + +2001 => array('Die Anzahl der Farben ist nicht gleich der Anzahl der Vorlagen in BarPlot::SetPattern().',0), +2002 => array('Unbekannte Vorlage im Aufruf von BarPlot::SetPattern().',0), +2003 => array('Anzahl der X- und Y-Koordinaten sind nicht identisch. Anzahl der X-Koordinaten: %d; Anzahl der Y-Koordinaten: %d.',2), +2004 => array('Alle Werte fÃŒr ein Balkendiagramm (barplot) mÃŒssen numerisch sein. Du hast den Wert nr [%d] == %s angegeben.',2), +2005 => array('Du hast einen leeren Vektor fÃŒr die Schattierungsfarben im Balkendiagramm (barplot) angegeben.',0), +2006 => array('Unbekannte Position fÃŒr die Werte der Balken: %s.',1), +2007 => array('Kann GroupBarPlot nicht aus einem leeren Vektor erzeugen.',0), +2008 => array('GroupBarPlot Element nbr %d wurde nicht definiert oder ist leer.',0), +2009 => array('Eins der Objekte, das an GroupBar weitergegeben wurde ist kein Balkendiagramm (BarPlot). Versichere Dich, dass Du den GroupBarPlot aus einem Vektor von Balkendiagrammen (barplot) oder AccBarPlot-Objekten erzeugst. (Class = %s)',1), +2010 => array('Kann AccBarPlot nicht aus einem leeren Vektor erzeugen.',0), +2011 => array('AccBarPlot-Element nbr %d wurde nicht definiert oder ist leer.',1), +2012 => array('Eins der Objekte, das an AccBar weitergegeben wurde ist kein Balkendiagramm (barplot). Versichere Dich, dass Du den AccBar-Plot aus einem Vektor von Balkendiagrammen (barplot) erzeugst. (Class=%s)',1), +2013 => array('Du hast einen leeren Vektor fÃŒr die Schattierungsfarben im Balkendiagramm (barplot) angegeben.',0), +2014 => array('Die Anzahl der Datenpunkte jeder Datenreihe in AccBarPlot muss gleich sein.',0), +2015 => array('Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-coordinates',0), + + +/* +** jpgraph_date +*/ + +3001 => array('Es ist nur möglich, entweder SetDateAlign() oder SetTimeAlign() zu benutzen, nicht beides!',0), + +/* +** jpgraph_error +*/ + +4002 => array('Fehler bei den Eingabedaten von LineErrorPlot. Die Anzahl der Datenpunkte mus ein Mehrfaches von drei sein!',0), + +/* +** jpgraph_flags +*/ + +5001 => array('Unbekannte Flaggen-Größe (%d).',1), +5002 => array('Der Flaggen-Index %s existiert nicht.',1), +5003 => array('Es wurde eine ungÃŒltige Ordnungszahl (%d) fÃŒr den Flaggen-Index angegeben.',1), +5004 => array('Der Landesname %s hat kein korrespondierendes Flaggenbild. Die Flagge mag existieren, abr eventuell unter einem anderen Namen, z.B. versuche "united states" statt "usa".',1), + + +/* +** jpgraph_gantt +*/ + +6001 => array('Interner Fehler. Die Höhe fÃŒr ActivityTitles ist < 0.',0), +6002 => array('Es dÃŒrfen keine negativen Werte fÃŒr die Gantt-Diagramm-Dimensionen angegeben werden. Verwende 0, wenn die Dimensionen automatisch ermittelt werden sollen.',0), +6003 => array('UngÃŒltiges Format fÃŒr den Bedingungs-Parameter bei Index=%d in CreateSimple(). Der Parameter muss bei index 0 starten und Vektoren in der Form (Row,Constrain-To,Constrain-Type) enthalten.',1), +6004 => array('UngÃŒltiges Format fÃŒr den Fortschritts-Parameter bei Index=%d in CreateSimple(). Der Parameter muss bei Index 0 starten und Vektoren in der Form (Row,Progress) enthalten.',1), +6005 => array('SetScale() ist nicht sinnvoll bei Gantt-Diagrammen.',0), +6006 => array('Das Gantt-Diagramm kann nicht automatisch skaliert werden. Es existieren keine AktivitÀten mit Termin. [GetBarMinMax() start >= n]',0), +6007 => array('PlausibiltÀtsprÃŒfung fÃŒr die automatische Gantt-Diagramm-Größe schlug fehl. Entweder die Breite (=%d) oder die Höhe (=%d) ist größer als MAX_GANTTIMG_SIZE. Dies kann möglicherweise durch einen falschen Wert bei einer AktivitÀt hervorgerufen worden sein.',2), +6008 => array('Du hast eine Bedingung angegeben von Reihe=%d bis Reihe=%d, die keine AktivitÀt hat.',2), +6009 => array('Unbekannter Bedingungstyp von Reihe=%d bis Reihe=%d',2), +6010 => array('UngÃŒltiger Icon-Index fÃŒr das eingebaute Gantt-Icon [%d]',1), +6011 => array('Argument fÃŒr IconImage muss entweder ein String oder ein Integer sein.',0), +6012 => array('Unbekannter Typ bei der Gantt-Objekt-Title-Definition.',0), +6015 => array('UngÃŒltige vertikale Position %d',1), +6016 => array('Der eingegebene Datums-String (%s) fÃŒr eine Gantt-AktivitÀt kann nicht interpretiert werden. Versichere Dich, dass es ein gÃŒltiger Datumsstring ist, z.B. 2005-04-23 13:30',1), +6017 => array('Unbekannter Datumstyp in GanttScale (%s).',1), +6018 => array('Intervall fÃŒr Minuten muss ein gerader Teiler einer Stunde sein, z.B. 1,5,10,12,15,20,30, etc. Du hast ein Intervall von %d Minuten angegeben.',1), +6019 => array('Die vorhandene Breite (%d) fÃŒr die Minuten ist zu klein, um angezeigt zu werden. Bitte benutze die automatische Größenermittlung oder vergrößere die Breite des Diagramms.',1), +6020 => array('Das Intervall fÃŒr die Stunden muss ein gerader Teiler eines Tages sein, z.B. 0:30, 1:00, 1:30, 4:00, etc. Du hast ein Intervall von %d eingegeben.',1), +6021 => array('Unbekanntes Format fÃŒr die Woche.',0), +6022 => array('Die Gantt-Skala wurde nicht eingegeben.',0), +6023 => array('Wenn Du sowohl Stunden als auch Minuten anzeigen lassen willst, muss das Stunden-Interval gleich 1 sein (anderenfalls ist es nicht sinnvoll, Minuten anzeigen zu lassen).',0), +6024 => array('Das CSIM-Ziel muss als String angegeben werden. Der Start des Ziels ist: %d',1), +6025 => array('Der CSIM-Alt-Text muss als String angegeben werden. Der Beginn des Alt-Textes ist: %d',1), +6027 => array('Der Fortschrittswert muss im Bereich [0, 1] liegen.',0), +6028 => array('Die eingegebene Höhe (%d) fÃŒr GanttBar ist nicht im zulÀssigen Bereich.',1), +6029 => array('Der Offset fÃŒr die vertikale Linie muss im Bereich [0,1] sein.',0), +6030 => array('Unbekannte Pfeilrichtung fÃŒr eine Verbindung.',0), +6031 => array('Unbekannter Pfeiltyp fÃŒr eine Verbindung.',0), +6032 => array('Interner Fehler: Unbekannter Pfadtyp (=%d) fÃŒr eine Verbindung.',1), +6033 => array('Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)',0), + +/* +** jpgraph_gradient +*/ + +7001 => array('Unbekannter Gradiententyp (=%d).',1), + +/* +** jpgraph_iconplot +*/ + +8001 => array('Der Mix-Wert fÃŒr das Icon muss zwischen 0 und 100 sein.',0), +8002 => array('Die Ankerposition fÃŒr Icons muss entweder "top", "bottom", "left", "right" oder "center" sein.',0), +8003 => array('Es ist nicht möglich, gleichzeitig ein Bild und eine Landesflagge fÃŒr dasselbe Icon zu definieren',0), +8004 => array('Wenn Du Landesflaggen benutzen willst, musst Du die Datei "jpgraph_flags.php" hinzufÃŒgen (per include).',0), + +/* +** jpgraph_imgtrans +*/ + +9001 => array('Der Wert fÃŒr die Bildtransformation ist außerhalb des zulÀssigen Bereichs. Der verschwindende Punkt am Horizont muss als Wert zwischen 0 und 1 angegeben werden.',0), + +/* +** jpgraph_lineplot +*/ + +10001 => array('Die Methode LinePlot::SetFilled() sollte nicht mehr benutzt werden. Benutze lieber SetFillColor()',0), +10002 => array('Der Plot ist zu kompliziert fÃŒr FastLineStroke. Benutze lieber den StandardStroke()',0), +10003 => array('Each plot in an accumulated lineplot must have the same number of data points.',0), +/* +** jpgraph_log +*/ + +11001 => array('Deine Daten enthalten nicht-numerische Werte.',0), +11002 => array('Negative Werte können nicht fÃŒr logarithmische Achsen verwendet werden.',0), +11003 => array('Deine Daten enthalten nicht-numerische Werte.',0), +11004 => array('Skalierungsfehler fÃŒr die logarithmische Achse. Es gibt ein Problem mit den Daten der Achse. Der größte Wert muss größer sein als Null. Es ist mathematisch nicht möglich, einen Wert gleich Null in der Skala zu haben.',0), +11005 => array('Das Tick-Intervall fÃŒr die logarithmische Achse ist nicht definiert. Lösche jeden Aufruf von SetTextLabelStart() oder SetTextTickInterval() bei der logarithmischen Achse.',0), + +/* +** jpgraph_mgraph +*/ + +12001 => array("Du benutzt GD 2.x und versuchst ein Nicht-Truecolor-Bild als Hintergrundbild zu benutzen. Um Hintergrundbilder mit GD 2.x zu benutzen, ist es notwendig Truecolor zu aktivieren, indem die USE_TRUECOLOR-Konstante auf TRUE gesetzt wird. Wegen eines Bugs in GD 2.0.1 ist die QualitÀt der Truetype-Schriften sehr schlecht, wenn man Truetype-Schriften mit Truecolor-Bildern verwendet.",0), +12002 => array('UngÃŒltiger Dateiname fÃŒr MGraph::SetBackgroundImage() : %s. Die Datei muss eine gÃŒltige Dateierweiterung haben (jpg,gif,png), wenn die automatische Typerkennung verwendet wird.',1), +12003 => array('Unbekannte Dateierweiterung (%s) in MGraph::SetBackgroundImage() fÃŒr Dateiname: %s',2), +12004 => array('Das Bildformat des Hintergrundbildes (%s) wird von Deiner System-Konfiguration nicht unterstÃŒtzt. ',1), +12005 => array('Das Hintergrundbild kann nicht gelesen werden: %s',1), +12006 => array('Es wurden ungÃŒltige Größen fÃŒr Breite oder Höhe beim Erstellen des Bildes angegeben, (Breite=%d, Höhe=%d)',2), +12007 => array('Das Argument fÃŒr MGraph::Add() ist nicht gÃŒltig fÃŒr GD.',0), +12008 => array('Deine PHP- (und GD-lib-) Installation scheint keine bekannten Bildformate zu unterstÃŒtzen.',0), +12009 => array('Deine PHP-Installation unterstÃŒtzt das gewÀhlte Bildformat nicht: %s',1), +12010 => array('Es konnte kein Bild als Datei %s erzeugt werden. ÜberprÃŒfe, ob Du die entsprechenden Schreibrechte im aktuellen Verzeichnis hast.',1), +12011 => array('Es konnte kein Truecolor-Bild erzeugt werden. ÜberprÃŒfe, ob Du wirklich die GD2-Bibliothek installiert hast.',0), +12012 => array('Es konnte kein Bild erzeugt werden. ÜberprÃŒfe, ob Du wirklich die GD2-Bibliothek installiert hast.',0), + +/* +** jpgraph_pie3d +*/ + +14001 => array('Pie3D::ShowBorder(). Missbilligte Funktion. Benutze Pie3D::SetEdge(), um die Ecken der TortenstÃŒcke zu kontrollieren.',0), +14002 => array('PiePlot3D::SetAngle() 3D-Torten-Projektionswinkel muss zwischen 5 und 85 Grad sein.',0), +14003 => array('Interne Festlegung schlug fehl. Pie3D::Pie3DSlice',0), +14004 => array('TortenstÃŒck-Startwinkel muss zwischen 0 und 360 Grad sein.',0), +14005 => array('Pie3D Interner Fehler: Versuch, zweimal zu umhÃŒllen bei der Suche nach dem Startindex.',0,), +14006 => array('Pie3D Interner Fehler: Z-Sortier-Algorithmus fÃŒr 3D-Tortendiagramme funktioniert nicht einwandfrei (2). Versuch, zweimal zu umhÃŒllen beim Erstellen des Bildes.',0), +14007 => array('Die Breite fÃŒr das 3D-Tortendiagramm ist 0. Gib eine Breite > 0 an.',0), + +/* +** jpgraph_pie +*/ + +15001 => array('PiePLot::SetTheme() Unbekannter Stil: %s',1), +15002 => array('Argument fÃŒr PiePlot::ExplodeSlice() muss ein Integer-Wert sein',0), +15003 => array('Argument fÃŒr PiePlot::Explode() muss ein Vektor mit Integer-Werten sein.',0), +15004 => array('TortenstÃŒck-Startwinkel muss zwischen 0 und 360 Grad sein.',0), +15005 => array('PiePlot::SetFont() sollte nicht mehr verwendet werden. Benutze stattdessen PiePlot->value->SetFont().',0), +15006 => array('PiePlot::SetSize() Radius fÃŒr Tortendiagramm muss entweder als Bruch [0, 0.5] der Bildgröße oder als Absoluwert in Pixel im Bereich [10, 1000] angegeben werden.',0), +15007 => array('PiePlot::SetFontColor() sollte nicht mehr verwendet werden. Benutze stattdessen PiePlot->value->SetColor()..',0), +15008 => array('PiePlot::SetLabelType() der Typ fÃŒr Tortendiagramme muss entweder 0 or 1 sein (nicht %d).',1), +15009 => array('UngÃŒltiges Tortendiagramm. Die Summe aller Daten ist Null.',0), +15010 => array('Die Summe aller Daten ist Null.',0), +15011 => array('Um Bildtransformationen benutzen zu können, muss die Datei jpgraph_imgtrans.php eingefÃŒgt werden (per include).',0), + +/* +** jpgraph_plotband +*/ + +16001 => array('Die Dichte fÃŒr das Pattern muss zwischen 1 und 100 sein. (Du hast %f eingegeben)',1), +16002 => array('Es wurde keine Position fÃŒr das Pattern angegeben.',0), +16003 => array('Unbekannte Pattern-Definition (%d)',0), +16004 => array('Der Mindeswert fÃŒr das PlotBand ist größer als der Maximalwert. Bitte korrigiere dies!',0), + + +/* +** jpgraph_polar +*/ + +17001 => array('PolarPlots mÃŒssen eine gerade Anzahl von Datenpunkten haben. Jeder Datenpunkt ist ein Tupel (Winkel, Radius).',0), +17002 => array('Unbekannte Ausrichtung fÃŒr X-Achsen-Titel. (%s)',1), +//17003 => array('Set90AndMargin() wird fÃŒr PolarGraph nicht unterstÃŒtzt.',0), +17004 => array('Unbekannter Achsentyp fÃŒr PolarGraph. Er muss entweder \'lin\' oder \'log\' sein.',0), + +/* +** jpgraph_radar +*/ + +18001 => array('ClientSideImageMaps werden fÃŒr RadarPlots nicht unterstÃŒtzt.',0), +18002 => array('RadarGraph::SupressTickMarks() sollte nicht mehr verwendet werden. Benutze stattdessen HideTickMarks().',0), +18003 => array('UngÃŒltiger Achsentyp fÃŒr RadarPlot (%s). Er muss entweder \'lin\' oder \'log\' sein.',1), +18004 => array('Die RadarPlot-Größe muss zwischen 0.1 und 1 sein. (Dein Wert=%f)',1), +18005 => array('RadarPlot: nicht unterstÃŒtzte Tick-Dichte: %d',1), +18006 => array('Minimum Daten %f (RadarPlots sollten nur verwendet werden, wenn alle Datenpunkte einen Wert > 0 haben).',1), +18007 => array('Die Anzahl der Titel entspricht nicht der Anzahl der Datenpunkte.',0), +18008 => array('Jeder RadarPlot muss die gleiche Anzahl von Datenpunkten haben.',0), + +/* +** jpgraph_regstat +*/ + +19001 => array('Spline: Anzahl der X- und Y-Koordinaten muss gleich sein.',0), +19002 => array('UngÃŒltige Dateneingabe fÃŒr Spline. Zwei oder mehr aufeinanderfolgende X-Werte sind identisch. Jeder eigegebene X-Wert muss unterschiedlich sein, weil vom mathematischen Standpunkt ein Eins-zu-Eins-Mapping vorliegen muss, d.h. jeder X-Wert korrespondiert mit exakt einem Y-Wert.',0), +19003 => array('Bezier: Anzahl der X- und Y-Koordinaten muss gleich sein.',0), + +/* +** jpgraph_scatter +*/ + +20001 => array('Fieldplots mÃŒssen die gleiche Anzahl von X und Y Datenpunkten haben.',0), +20002 => array('Bei Fieldplots muss ein Winkel fÃŒr jeden X und Y Datenpunkt angegeben werden.',0), +20003 => array('Scatterplots mÃŒssen die gleiche Anzahl von X- und Y-Datenpunkten haben.',0), + +/* +** jpgraph_stock +*/ + +21001 => array('Die Anzahl der Datenwerte fÃŒr Stock-Charts mÃŒssen ein Mehrfaches von %d Datenpunkten sein.',1), + +/* +** jpgraph_plotmark +*/ + +23001 => array('Der Marker "%s" existiert nicht in der Farbe: %d',2), +23002 => array('Der Farb-Index ist zu hoch fÃŒr den Marker "%s"',1), +23003 => array('Ein Dateiname muss angegeben werden, wenn Du den Marker-Typ auf MARK_IMG setzt.',0), + +/* +** jpgraph_utils +*/ + +24001 => array('FuncGenerator : Keine Funktion definiert. ',0), +24002 => array('FuncGenerator : Syntax-Fehler in der Funktionsdefinition ',0), +24003 => array('DateScaleUtils: Unknown tick type specified in call to GetTicks()',0), +24004 => array('ReadCSV2: Die anzahl der spalten fehler in %s reihe %d',2), +/* +** jpgraph +*/ + +25001 => array('Diese PHP-Installation ist nicht mit der GD-Bibliothek kompiliert. Bitte kompiliere PHP mit GD-UnterstÃŒtzung neu, damit JpGraph funktioniert. (Weder die Funktion imagetypes() noch imagecreatefromstring() existiert!)',0), +25002 => array('Diese PHP-Installation scheint nicht die benötigte GD-Bibliothek zu unterstÃŒtzen. Bitte schau in der PHP-Dokumentation nach, wie man die GD-Bibliothek installiert und aktiviert.',0), +25003 => array('Genereller PHP Fehler : Bei %s:%d : %s',3), +25004 => array('Genereller PHP Fehler : %s ',1), +25005 => array('PHP_SELF, die PHP-Global-Variable kann nicht ermittelt werden. PHP kann nicht von der Kommandozeile gestartet werden, wenn der Cache oder die Bilddateien automatisch benannt werden sollen.',0), +25006 => array('Die Benutzung der FF_CHINESE (FF_BIG5) Schriftfamilie benötigt die iconv() Funktion in Deiner PHP-Konfiguration. Dies wird nicht defaultmÀßig in PHP kompiliert (benötigt "--width-iconv" bei der Konfiguration).',0), +25007 => array('Du versuchst das lokale (%s) zu verwenden, was von Deiner PHP-Installation nicht unterstÃŒtzt wird. Hinweis: Benutze \'\', um das defaultmÀßige Lokale fÃŒr diese geographische Region festzulegen.',1), +25008 => array('Die Bild-Breite und Höhe in Graph::Graph() mÃŒssen numerisch sein',0), +25009 => array('Die Skalierung der Achsen muss angegeben werden mit Graph::SetScale()',0), + +25010 => array('Graph::Add() Du hast versucht, einen leeren Plot zum Graph hinzuzufÃŒgen.',0), +25011 => array('Graph::AddY2() Du hast versucht, einen leeren Plot zum Graph hinzuzufÃŒgen.',0), +25012 => array('Graph::AddYN() Du hast versucht, einen leeren Plot zum Graph hinzuzufÃŒgen.',0), +25013 => array('Es können nur Standard-Plots zu multiplen Y-Achsen hinzugefÃŒgt werden',0), +25014 => array('Graph::AddText() Du hast versucht, einen leeren Text zum Graph hinzuzufÃŒgen.',0), +25015 => array('Graph::AddLine() Du hast versucht, eine leere Linie zum Graph hinzuzufÃŒgen.',0), +25016 => array('Graph::AddBand() Du hast versucht, ein leeres Band zum Graph hinzuzufÃŒgen.',0), +25017 => array('Du benutzt GD 2.x und versuchst, ein Hintergrundbild in einem Truecolor-Bild zu verwenden. Um Hintergrundbilder mit GD 2.x zu verwenden, ist es notwendig, Truecolor zu aktivieren, indem die USE_TRUECOLOR-Konstante auf TRUE gesetzt wird. Wegen eines Bugs in GD 2.0.1 ist die QualitÀt der Schrift sehr schlecht, wenn Truetype-Schrift in Truecolor-Bildern verwendet werden.',0), +25018 => array('Falscher Dateiname fÃŒr Graph::SetBackgroundImage() : "%s" muss eine gÃŒltige Dateinamenerweiterung (jpg,gif,png) haben, wenn die automatische Dateityperkennung verwenndet werden soll.',1), +25019 => array('Unbekannte Dateinamenerweiterung (%s) in Graph::SetBackgroundImage() fÃŒr Dateiname: "%s"',2), + +25020 => array('Graph::SetScale(): Dar Maximalwert muss größer sein als der Mindestwert.',0), +25021 => array('Unbekannte Achsendefinition fÃŒr die Y-Achse. (%s)',1), +25022 => array('Unbekannte Achsendefinition fÃŒr die X-Achse. (%s)',1), +25023 => array('Nicht unterstÃŒtzter Y2-Achsentyp: "%s" muss einer von (lin,log,int) sein.',1), +25024 => array('Nicht unterstÃŒtzter X-Achsentyp: "%s" muss einer von (lin,log,int) sein.',1), +25025 => array('Nicht unterstÃŒtzte Tick-Dichte: %d',1), +25026 => array('Nicht unterstÃŒtzter Typ der nicht angegebenen Y-Achse. Du hast entweder: 1. einen Y-Achsentyp fÃŒr automatisches Skalieren definiert, aber keine Plots angegeben. 2. eine Achse direkt definiert, aber vergessen, die Tick-Dichte zu festzulegen.',0), +25027 => array('Kann cached CSIM "%s" zum Lesen nicht öffnen.',1), +25028 => array('Apache/PHP hat keine Schreibrechte, in das CSIM-Cache-Verzeichnis (%s) zu schreiben. ÜberprÃŒfe die Rechte.',1), +25029 => array('Kann nicht in das CSIM "%s" schreiben. ÜberprÃŒfe die Schreibrechte und den freien Speicherplatz.',1), + +25030 => array('Fehlender Skriptname fÃŒr StrokeCSIM(). Der Name des aktuellen Skriptes muss als erster Parameter von StrokeCSIM() angegeben werden.',0), +25031 => array('Der Achsentyp muss mittels Graph::SetScale() angegeben werden.',0), +25032 => array('Es existieren keine Plots fÃŒr die Y-Achse nbr:%d',1), +25033 => array('',0), +25034 => array('Undefinierte X-Achse kann nicht gezeichnet werden. Es wurden keine Plots definiert.',0), +25035 => array('Du hast Clipping aktiviert. Clipping wird nur fÃŒr Diagramme mit 0 oder 90 Grad Rotation unterstÃŒtzt. Bitte verÀndere Deinen Rotationswinkel (=%d Grad) dementsprechend oder deaktiviere Clipping.',1), +25036 => array('Unbekannter Achsentyp AxisStyle() : %s',1), +25037 => array('Das Bildformat Deines Hintergrundbildes (%s) wird von Deiner System-Konfiguration nicht unterstÃŒtzt. ',1), +25038 => array('Das Hintergrundbild scheint von einem anderen Typ (unterschiedliche Dateierweiterung) zu sein als der angegebene Typ. Angegebenen: %s; Datei: %s',2), +25039 => array('Hintergrundbild kann nicht gelesen werden: "%s"',1), + +25040 => array('Es ist nicht möglich, sowohl ein Hintergrundbild als auch eine Hintergrund-Landesflagge anzugeben.',0), +25041 => array('Um Landesflaggen als Hintergrund benutzen zu können, muss die Datei "jpgraph_flags.php" eingefÃŒgt werden (per include).',0), +25042 => array('Unbekanntes Hintergrundbild-Layout',0), +25043 => array('Unbekannter Titelhintergrund-Stil.',0), +25044 => array('Automatisches Skalieren kann nicht verwendet werden, weil es unmöglich ist, einen gÃŒltigen min/max Wert fÃŒr die Y-Achse zu ermitteln (nur Null-Werte).',0), +25045 => array('Die Schriftfamilien FF_HANDWRT und FF_BOOK sind wegen Copyright-Problemen nicht mehr verfÃŒgbar. Diese Schriften können nicht mehr mit JpGraph verteilt werden. Bitte lade Dir Schriften von http://corefonts.sourceforge.net/ herunter.',0), +25046 => array('Angegebene TTF-Schriftfamilie (id=%d) ist unbekannt oder existiert nicht. Bitte merke Dir, dass TTF-Schriften wegen Copyright-Problemen nicht mit JpGraph mitgeliefert werden. Du findest MS-TTF-Internetschriften (arial, courier, etc.) zum Herunterladen unter http://corefonts.sourceforge.net/',1), +25047 => array('Stil %s ist nicht verfÃŒgbar fÃŒr Schriftfamilie %s',2), +25048 => array('Unbekannte Schriftstildefinition [%s].',1), +25049 => array('Schriftdatei "%s" ist nicht lesbar oder existiert nicht.',1), + +25050 => array('Erstes Argument fÃŒr Text::Text() muss ein String sein.',0), +25051 => array('UngÃŒltige Richtung angegeben fÃŒr Text.',0), +25052 => array('PANIK: Interner Fehler in SuperScript::Stroke(). Unbekannte vertikale Ausrichtung fÃŒr Text.',0), +25053 => array('PANIK: Interner Fehler in SuperScript::Stroke(). Unbekannte horizontale Ausrichtung fÃŒr Text.',0), +25054 => array('Interner Fehler: Unbekannte Grid-Achse %s',1), +25055 => array('Axis::SetTickDirection() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetTickSide().',0), +25056 => array('SetTickLabelMargin() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetLabelMargin().',0), +25057 => array('SetTextTicks() sollte nicht mehr verwendet werden. Benutze stattdessen SetTextTickInterval().',0), +25058 => array('TextLabelIntevall >= 1 muss angegeben werden.',0), +25059 => array('SetLabelPos() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetLabelSide().',0), + +25060 => array('Unbekannte Ausrichtung angegeben fÃŒr X-Achsentitel (%s).',1), +25061 => array('Unbekannte Ausrichtung angegeben fÃŒr Y-Achsentitel (%s).',1), +25062 => array('Label unter einem Winkel werden fÃŒr die Y-Achse nicht unterstÃŒtzt.',0), +25063 => array('Ticks::SetPrecision() sollte nicht mehr verwendet werden. Benutze stattdessen Ticks::SetLabelFormat() (oder Ticks::SetFormatCallback()).',0), +25064 => array('Kleinere oder größere Schrittgröße ist 0. ÜberprÃŒfe, ob Du fÀlschlicherweise SetTextTicks(0) in Deinem Skript hast. Wenn dies nicht der Fall ist, bist Du eventuell ÃŒber einen Bug in JpGraph gestolpert. Bitte sende einen Report und fÃŒge den Code an, der den Fehler verursacht hat.',0), +25065 => array('Tick-Positionen mÃŒssen als array() angegeben werden',0), +25066 => array('Wenn die Tick-Positionen und -Label von Hand eingegeben werden, muss die Anzahl der Ticks und der Label gleich sein.',0), +25067 => array('Deine von Hand eingegebene Achse und Ticks sind nicht korrekt. Die Skala scheint zu klein zu sein fÃŒr den Tickabstand.',0), +25068 => array('Ein Plot hat eine ungÃŒltige Achse. Dies kann beispielsweise der Fall sein, wenn Du automatisches Text-Skalieren verwendest, um ein Liniendiagramm zu zeichnen mit nur einem Datenpunkt, oder wenn die BildflÀche zu klein ist. Es kann auch der Fall sein, dass kein Datenpunkt einen numerischen Wert hat (vielleicht nur \'-\' oder \'x\').',0), +25069 => array('Grace muss größer sein als 0',0), + +25070 => array('Deine Daten enthalten nicht-numerische Werte.',0), +25071 => array('Du hast mit SetAutoMin() einen Mindestwert angegeben, der größer ist als der Maximalwert fÃŒr die Achse. Dies ist nicht möglich.',0), +25072 => array('Du hast mit SetAutoMax() einen Maximalwert angegeben, der kleiner ist als der Minimalwert der Achse. Dies ist nicht möglich.',0), +25073 => array('Interner Fehler. Der Integer-Skalierungs-Algorithmus-Vergleich ist außerhalb der Grenzen (r=%f).',1), +25074 => array('Interner Fehler. Der Skalierungsbereich ist negativ (%f) [fÃŒr %s Achse]. Dieses Problem könnte verursacht werden durch den Versuch, \'ungÃŒltige\' Werte in die Daten-Vektoren einzugeben (z.B. nur String- oder NULL-Werte), was beim automatischen Skalieren einen Fehler erzeugt.',2), +25075 => array('Die automatischen Ticks können nicht gesetzt werden, weil min==max.',0), +25077 => array('Einstellfaktor fÃŒr die Farbe muss größer sein als 0',0), +25078 => array('Unbekannte Farbe: %s',1), +25079 => array('Unbekannte Farbdefinition: %s, Größe=%d',2), + +25080 => array('Der Alpha-Parameter fÃŒr Farben muss zwischen 0.0 und 1.0 liegen.',0), +25081 => array('Das ausgewÀhlte Grafikformat wird entweder nicht unterstÃŒtzt oder ist unbekannt [%s]',1), +25082 => array('Es wurden ungÃŒltige Größen fÃŒr Breite und Höhe beim Erstellen des Bildes definiert (Breite=%d, Höhe=%d).',2), +25083 => array('Es wurde eine ungÃŒltige Größe beim Kopieren des Bildes angegeben. Die Größe fÃŒr das kopierte Bild wurde auf 1 Pixel oder weniger gesetzt.',0), +25084 => array('Fehler beim Erstellen eines temporÀren GD-Canvas. Möglicherweise liegt ein Arbeitsspeicherproblem vor.',0), +25085 => array('Ein Bild kann nicht aus dem angegebenen String erzeugt werden. Er ist entweder in einem nicht unterstÃŒtzen Format oder er represÀntiert ein kaputtes Bild.',0), +25086 => array('Du scheinst nur GD 1.x installiert zu haben. Um Alphablending zu aktivieren, ist GD 2.x oder höher notwendig. Bitte installiere GD 2.x oder versichere Dich, dass die Konstante USE_GD2 richtig gesetzt ist. StandardmÀßig wird die installierte GD-Version automatisch erkannt. Ganz selten wird GD2 erkannt, obwohl nur GD1 installiert ist. Die Konstante USE_GD2 muss dann zu "false" gesetzt werden.',0), +25087 => array('Diese PHP-Version wurde ohne TTF-UnterstÃŒtzung konfiguriert. PHP muss mit TTF-UnterstÃŒtzung neu kompiliert und installiert werden.',0), +25088 => array('Die GD-SchriftunterstÃŒtzung wurde falsch konfiguriert. Der Aufruf von imagefontwidth() ist fehlerhaft.',0), +25089 => array('Die GD-SchriftunterstÃŒtzung wurde falsch konfiguriert. Der Aufruf von imagefontheight() ist fehlerhaft.',0), + +25090 => array('Unbekannte Richtung angegeben im Aufruf von StrokeBoxedText() [%s].',1), +25091 => array('Die interne Schrift untestÃŒtzt das Schreiben von Text in einem beliebigen Winkel nicht. Benutze stattdessen TTF-Schriften.',0), +25092 => array('Es liegt entweder ein Konfigurationsproblem mit TrueType oder ein Problem beim Lesen der Schriftdatei "%s" vor. Versichere Dich, dass die Datei existiert und Leserechte und -pfad vergeben sind. (wenn \'basedir\' restriction in PHP aktiviert ist, muss die Schriftdatei im Dokumentwurzelverzeichnis abgelegt werden). Möglicherweise ist die FreeType-Bibliothek falsch installiert. Versuche, mindestens zur FreeType-Version 2.1.13 zu aktualisieren und kompiliere GD mit einem korrekten Setup neu, damit die FreeType-Bibliothek gefunden werden kann.',1), +25093 => array('Die Schriftdatei "%s" kann nicht gelesen werden beim Aufruf von Image::GetBBoxTTF. Bitte versichere Dich, dass die Schrift gesetzt wurde, bevor diese Methode aufgerufen wird, und dass die Schrift im TTF-Verzeichnis installiert ist.',1), +25094 => array('Die Textrichtung muss in einem Winkel zwischen 0 und 90 engegeben werden.',0), +25095 => array('Unbekannte Schriftfamilien-Definition. ',0), +25096 => array('Der Farbpalette können keine weiteren Farben zugewiesen werden. Dem Bild wurde bereits die größtmögliche Anzahl von Farben (%d) zugewiesen und die Palette ist voll. Verwende stattdessen ein TrueColor-Bild',0), +25097 => array('Eine Farbe wurde als leerer String im Aufruf von PushColor() angegegeben.',0), +25098 => array('Negativer Farbindex. Unpassender Aufruf von PopColor().',0), +25099 => array('Die Parameter fÃŒr Helligkeit und Kontrast sind außerhalb des zulÀssigen Bereichs [-1,1]',0), + +25100 => array('Es liegt ein Problem mit der Farbpalette und dem GD-Setup vor. Bitte deaktiviere anti-aliasing oder verwende GD2 mit TrueColor. Wenn die GD2-Bibliothek installiert ist, versichere Dich, dass die Konstante USE_GD2 auf "true" gesetzt und TrueColor aktiviert ist.',0), +25101 => array('UngÃŒltiges numerisches Argument fÃŒr SetLineStyle(): (%d)',1), +25102 => array('UngÃŒltiges String-Argument fÃŒr SetLineStyle(): %s',1), +25103 => array('UngÃŒltiges Argument fÃŒr SetLineStyle %s',1), +25104 => array('Unbekannter Linientyp: %s',1), +25105 => array('Es wurden NULL-Daten fÃŒr ein gefÃŒlltes Polygon angegeben. Sorge dafÃŒr, dass keine NULL-Daten angegeben werden.',0), +25106 => array('Image::FillToBorder : es können keine weiteren Farben zugewiesen werden.',0), +25107 => array('In Datei "%s" kann nicht geschrieben werden. ÜberprÃŒfe die aktuellen Schreibrechte.',1), +25108 => array('Das Bild kann nicht gestreamt werden. Möglicherweise liegt ein Fehler im PHP/GD-Setup vor. Kompiliere PHP neu und verwende die eingebaute GD-Bibliothek, die mit PHP angeboten wird.',0), +25109 => array('Deine PHP- (und GD-lib-) Installation scheint keine bekannten Grafikformate zu unterstÃŒtzen. Sorge zunÀchst dafÃŒr, dass GD als PHP-Modul kompiliert ist. Wenn Du außerdem JPEG-Bilder verwenden willst, musst Du die JPEG-Bibliothek installieren. Weitere Details sind in der PHP-Dokumentation zu finden.',0), + +25110 => array('Dein PHP-Installation unterstÃŒtzt das gewÀhlte Grafikformat nicht: %s',1), +25111 => array('Das gecachete Bild %s kann nicht gelöscht werden. Problem mit den Rechten?',1), +25112 => array('Das Datum der gecacheten Datei (%s) liegt in der Zukunft.',1), +25113 => array('Das gecachete Bild %s kann nicht gelöscht werden. Problem mit den Rechten?',1), +25114 => array('PHP hat nicht die erforderlichen Rechte, um in die Cache-Datei %s zu schreiben. Bitte versichere Dich, dass der Benutzer, der PHP anwendet, die entsprechenden Schreibrechte fÃŒr die Datei hat, wenn Du das Cache-System in JPGraph verwenden willst.',1), +25115 => array('Berechtigung fÃŒr gecachetes Bild %s kann nicht gesetzt werden. Problem mit den Rechten?',1), +25116 => array('Datei kann nicht aus dem Cache %s geöffnet werden',1), +25117 => array('Gecachetes Bild %s kann nicht zum Lesen geöffnet werden.',1), +25118 => array('Verzeichnis %s kann nicht angelegt werden. Versichere Dich, dass PHP die Schreibrechte in diesem Verzeichnis hat.',1), +25119 => array('Rechte fÃŒr Datei %s können nicht gesetzt werden. Problem mit den Rechten?',1), + +25120 => array('Die Position fÃŒr die Legende muss als Prozentwert im Bereich 0-1 angegeben werden.',0), +25121 => array('Eine leerer Datenvektor wurde fÃŒr den Plot eingegeben. Es muss wenigstens ein Datenpunkt vorliegen.',0), +25122 => array('Stroke() muss als Subklasse der Klasse Plot definiert sein.',0), +25123 => array('Du kannst keine Text-X-Achse mit X-Koordinaten verwenden. Benutze stattdessen eine "int" oder "lin" Achse.',0), +25124 => array('Der Eingabedatenvektor mus aufeinanderfolgende Werte von 0 aufwÀrts beinhalten. Der angegebene Y-Vektor beginnt mit leeren Werten (NULL).',0), +25125 => array('UngÃŒltige Richtung fÃŒr statische Linie.',0), +25126 => array('Es kann kein TrueColor-Bild erzeugt werden. ÜberprÃŒfe, ob die GD2-Bibliothek und PHP korrekt aufgesetzt wurden.',0), +25127 => array('The library has been configured for automatic encoding conversion of Japanese fonts. This requires that PHP has the mb_convert_encoding() function. Your PHP installation lacks this function (PHP needs the "--enable-mbstring" when compiled).',0), +25128 => array('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.',0), +25129 => array('Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines.',0), +25130 => array('Too small plot area. (%d x %d). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.',2), + +25131 => array('StrokeBoxedText2() only supports TTF fonts and not built-in bitmap fonts.',0), + +/* +** jpgraph_led +*/ + +25500 => array('Multibyte strings must be enabled in the PHP installation in order to run the LED module so that the function mb_strlen() is available. See PHP documentation for more information.',0), + + +/* +**--------------------------------------------------------------------------------------------- +** Pro-version strings +**--------------------------------------------------------------------------------------------- +*/ + +/* +** jpgraph_table +*/ + +27001 => array('GTextTable: UngÃŒltiges Argument fÃŒr Set(). Das Array-Argument muss 2-- dimensional sein.',0), +27002 => array('GTextTable: UngÃŒltiges Argument fÃŒr Set()',0), +27003 => array('GTextTable: Falsche Anzahl von Argumenten fÃŒr GTextTable::SetColor()',0), +27004 => array('GTextTable: Angegebener Zellenbereich, der verschmolzen werden soll, ist ungÃŒltig.',0), +27005 => array('GTextTable: Bereits verschmolzene Zellen im Bereich (%d,%d) bis (%d,%d) können nicht ein weiteres Mal verschmolzen werden.',4), +27006 => array('GTextTable: Spalten-Argument = %d liegt außerhalb der festgelegten Tabellengröße.',1), +27007 => array('GTextTable: Zeilen-Argument = %d liegt außerhalb der festgelegten Tabellengröße.',1), +27008 => array('GTextTable: Spalten- und Zeilengröße mÃŒssen zu den Dimensionen der Tabelle passen.',0), +27009 => array('GTextTable: Die Anzahl der Tabellenspalten oder -zeilen ist 0. Versichere Dich, dass die Methoden Init() oder Set() aufgerufen werden.',0), +27010 => array('GTextTable: Es wurde keine Ausrichtung beim Aufruf von SetAlign() angegeben.',0), +27011 => array('GTextTable: Es wurde eine unbekannte Ausrichtung beim Aufruf von SetAlign() abgegeben. Horizontal=%s, Vertikal=%s',2), +27012 => array('GTextTable: Interner Fehler. Es wurde ein ungÃŒltiges Argument festgeleget %s',1), +27013 => array('GTextTable: Das Argument fÃŒr FormatNumber() muss ein String sein.',0), +27014 => array('GTextTable: Die Tabelle wurde weder mit einem Aufruf von Set() noch von Init() initialisiert.',0), +27015 => array('GTextTable: Der Zellenbildbedingungstyp muss entweder TIMG_WIDTH oder TIMG_HEIGHT sein.',0), + +/* +** jpgraph_windrose +*/ + +22001 => array('Die Gesamtsumme der prozentualen Anteile aller Windrosenarme darf 100%% nicht ÃŒberschreiten!\n(Aktuell max: %d)',1), +22002 => array('Das Bild ist zu klein fÃŒr eine Skala. Bitte vergrößere das Bild.',0), +22004 => array('Die Etikettendefinition fÃŒr Windrosenrichtungen mÃŒssen 16 Werte haben (eine fÃŒr jede Kompassrichtung).',0), +22005 => array('Der Linientyp fÃŒr radiale Linien muss einer von ("solid","dotted","dashed","longdashed") sein.',0), +22006 => array('Es wurde ein ungÃŒltiger Windrosentyp angegeben.',0), +22007 => array('Es wurden zu wenig Werte fÃŒr die Bereichslegende angegeben.',0), +22008 => array('Interner Fehler: Versuch, eine freie Windrose zu plotten, obwohl der Typ keine freie Windrose ist.',0), +22009 => array('Du hast die gleiche Richtung zweimal angegeben, einmal mit einem Winkel und einmal mit einer Kompassrichtung (%f Grad).',0), +22010 => array('Die Richtung muss entweder ein numerischer Wert sein oder eine der 16 Kompassrichtungen',0), +22011 => array('Der Windrosenindex muss ein numerischer oder Richtungswert sein. Du hast angegeben Index=%d',1), +22012 => array('Die radiale Achsendefinition fÃŒr die Windrose enthÀlt eine nicht aktivierte Richtung.',0), +22013 => array('Du hast dasselbe Look&Feel fÃŒr die gleiche Kompassrichtung zweimal engegeben, einmal mit Text und einmal mit einem Index (Index=%d)',1), +22014 => array('Der Index fÃŒr eine Kompassrichtung muss zwischen 0 und 15 sein.',0), +22015 => array('Du hast einen unbekannten Windrosenplottyp angegeben.',0), +22016 => array('Der Windrosenarmindex muss ein numerischer oder ein Richtungswert sein.',0), +22017 => array('Die Windrosendaten enthalten eine Richtung, die nicht aktiviert ist. Bitte berichtige, welche Label angezeigt werden sollen.',0), +22018 => array('Du hast fÃŒr dieselbe Kompassrichtung zweimal Daten angegeben, einmal mit Text und einmal mit einem Index (Index=%d)',1), +22019 => array('Der Index fÃŒr eine Richtung muss zwischen 0 und 15 sein. Winkel dÃŒrfen nicht fÃŒr einen regelmÀßigen Windplot angegeben werden, sondern entweder ein Index oder eine Kompassrichtung.',0), +22020 => array('Der Windrosenplot ist zu groß fÃŒr die angegebene Bildgröße. Benutze entweder WindrosePlot::SetSize(), um den Plot kleiner zu machen oder vergrößere das Bild im ursprÃŒnglichen Aufruf von WindroseGraph().',0), +22021 => array('It is only possible to add Text, IconPlot or WindrosePlot to a Windrose Graph',0), + +/* +** jpgraph_odometer +*/ + +13001 => array('Unbekannter Nadeltypstil (%d).',1), +13002 => array('Ein Wert fÃŒr das Odometer (%f) ist außerhalb des angegebenen Bereichs [%f,%f]',3), + +/* +** jpgraph_barcode +*/ + +1001 => array('Unbekannte Kodier-Specifikation: %s',1), +1002 => array('datenvalidierung schlug fehl. [%s] kann nicht mittels der Kodierung "%s" kodiert werden',2), +1003 => array('Interner Kodierfehler. Kodieren von %s ist nicht möglich in Code 128',1), +1004 => array('Interner barcode Fehler. Unbekannter UPC-E Kodiertyp: %s',1), +1005 => array('Interner Fehler. Das Textzeichen-Tupel (%s, %s) kann nicht im Code-128 Zeichensatz C kodiert werden.',2), +1006 => array('Interner Kodierfehler fÃŒr CODE 128. Es wurde versucht, CTRL in CHARSET != A zu kodieren.',0), +1007 => array('Interner Kodierfehler fÃŒr CODE 128. Es wurde versucht, DEL in CHARSET != B zu kodieren.',0), +1008 => array('Interner Kodierfehler fÃŒr CODE 128. Es wurde versucht, kleine Buchstaben in CHARSET != B zu kodieren.',0), +1009 => array('Kodieren mittels CODE 93 wird noch nicht unterstÃŒtzt.',0), +1010 => array('Kodieren mittels POSTNET wird noch nicht unterstÃŒtzt.',0), +1011 => array('Nicht untrstÃŒtztes Barcode-Backend fÃŒr den Typ %s',1), + +/* +** PDF417 +*/ + +26000 => array('PDF417: The PDF417 module requires that the PHP installation must support the function bcmod(). This is normally enabled at compile time. See documentation for more information.',0), +26001 => array('PDF417: Die Anzahl der Spalten muss zwischen 1 und 30 sein.',0), +26002 => array('PDF417: Der Fehler-Level muss zwischen 0 und 8 sein.',0), +26003 => array('PDF417: UngÃŒltiges Format fÃŒr Eingabedaten, um sie mit PDF417 zu kodieren.',0), +26004 => array('PDF417: die eigebenen Daten können nicht mit Fehler-Level %d und %d spalten kodiert werden, weil daraus zu viele Symbole oder mehr als 90 Zeilen resultieren.',2), +26005 => array('PDF417: Die Datei "%s" kann nicht zum Schreiben geöffnet werden.',1), +26006 => array('PDF417: Interner Fehler. Die Eingabedatendatei fÃŒr PDF417-Cluster %d ist fehlerhaft.',1), +26007 => array('PDF417: Interner Fehler. GetPattern: UngÃŒltiger Code-Wert %d (Zeile %d)',2), +26008 => array('PDF417: Interner Fehler. Modus wurde nicht in der Modusliste!! Modus %d',1), +26009 => array('PDF417: Kodierfehler: UngÃŒltiges Zeichen. Zeichen kann nicht mit ASCII-Code %d kodiert werden.',1), +26010 => array('PDF417: Interner Fehler: Keine Eingabedaten beim Dekodieren.',0), +26011 => array('PDF417: Kodierfehler. Numerisches Kodieren bei nicht-numerischen Daten nicht möglich.',0), +26012 => array('PDF417: Interner Fehler. Es wurden fÃŒr den Binary-Kompressor keine Daten zum Dekodieren eingegeben.',0), +26013 => array('PDF417: Interner Fehler. Checksum Fehler. Koeffiziententabellen sind fehlerhaft.',0), +26014 => array('PDF417: Interner Fehler. Es wurden keine Daten zum Berechnen von Kodewörtern eingegeben.',0), +26015 => array('PDF417: Interner Fehler. Ein Eintrag 0 in die StatusÃŒbertragungstabellen ist nicht NULL. Eintrag 1 = (%s)',1), +26016 => array('PDF417: Interner Fehler: Nichtregistrierter StatusÃŒbertragungsmodus beim Dekodieren.',0), + + +/* +** jpgraph_contour +*/ + +28001 => array('Dritten parameter fur Contour muss ein vector der fargen sind.',0), +28002 => array('Die anzahlen der farges jeder isobar linien muss gleich sein.',0), +28003 => array('ContourPlot Interner Fehler: isobarHCrossing: Spalten index ist zu hoch (%d)',1), +28004 => array('ContourPlot Interner Fehler: isobarHCrossing: Reihe index ist zu hoch (%d)',1), +28005 => array('ContourPlot Interner Fehler: isobarVCrossing: Reihe index ist zu hoch (%d)',1), +28006 => array('ContourPlot Interner Fehler: isobarVCrossing: Spalten index ist zu hoch (%d)',1), +28007 => array('ContourPlot. Interpolation faktor ist zu hoch (>5)',0), + + +/* + * jpgraph_matrix and colormap +*/ +29201 => array('Min range value must be less or equal to max range value for colormaps',0), +29202 => array('The distance between min and max value is too small for numerical precision',0), +29203 => array('Number of color quantification level must be at least %d',1), +29204 => array('Number of colors (%d) is invalid for this colormap. It must be a number that can be written as: %d + k*%d',3), +29205 => array('Colormap specification out of range. Must be an integer in range [0,%d]',1), +29206 => array('Invalid object added to MatrixGraph',0), +29207 => array('Empty input data specified for MatrixPlot',0), +29208 => array('Unknown side specifiction for matrix labels "%s"',1), +29209 => array('CSIM Target matrix must be the same size as the data matrix (csim=%d x %d, data=%d x %d)',4), +29210 => array('CSIM Target for matrix labels does not match the number of labels (csim=%d, labels=%d)',2), + +); + +?> diff --git a/ext/jpgraph-3.0.7/src/lang/en.inc.php b/ext/jpgraph-3.0.7/src/lang/en.inc.php index 3d0961d..98f9220 100644 --- a/ext/jpgraph-3.0.7/src/lang/en.inc.php +++ b/ext/jpgraph-3.0.7/src/lang/en.inc.php @@ -1,536 +1,536 @@ -,) -$_jpg_messages = array( - -/* -** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text -*/ -10 => array('
      JpGraph Error: -HTTP headers have already been sent.
      Caused by output from file %s at line %d.
      Explanation:
      HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

      Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

      For example it is a common mistake to leave a blank line before the opening "<?php".

      ',2), - -/* -** Setup errors -*/ -11 => array('No path specified for CACHE_DIR. Please specify CACHE_DIR manually in jpg-config.inc',0), -12 => array('No path specified for TTF_DIR and path can not be determined automatically. Please specify TTF_DIR manually (in jpg-config.inc).',0), -13 => array('The installed PHP version (%s) is not compatible with this release of the library. The library requires at least PHP version %s',2), - - -/* -** jpgraph_bar -*/ - -2001 => array('Number of colors is not the same as the number of patterns in BarPlot::SetPattern()',0), -2002 => array('Unknown pattern specified in call to BarPlot::SetPattern()',0), -2003 => array('Number of X and Y points are not equal. Number of X-points: %d Number of Y-points: %d',2), -2004 => array('All values for a barplot must be numeric. You have specified value nr [%d] == %s',2), -2005 => array('You have specified an empty array for shadow colors in the bar plot.',0), -2006 => array('Unknown position for values on bars : %s',1), -2007 => array('Cannot create GroupBarPlot from empty plot array.',0), -2008 => array('Group bar plot element nbr %d is undefined or empty.',0), -2009 => array('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the GroupBar plot from an array of BarPlot or AccBarPlot objects. (Class = %s)',1), -2010 => array('Cannot create AccBarPlot from empty plot array.',0), -2011 => array('Acc bar plot element nbr %d is undefined or empty.',1), -2012 => array('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects. (Class=%s)',1), -2013 => array('You have specified an empty array for shadow colors in the bar plot.',0), -2014 => array('Number of datapoints for each data set in accbarplot must be the same',0), -2015 => array('Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-coordinates',0), - - -/* -** jpgraph_date -*/ - -3001 => array('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both',0), - -/* -** jpgraph_error -*/ - -4002 => array('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3',0), - -/* -** jpgraph_flags -*/ - -5001 => array('Unknown flag size (%d).',1), -5002 => array('Flag index %s does not exist.',1), -5003 => array('Invalid ordinal number (%d) specified for flag index.',1), -5004 => array('The (partial) country name %s does not have a corresponding flag image. The flag may still exist but under another name, e.g. instead of "usa" try "united states".',1), - - -/* -** jpgraph_gantt -*/ - -6001 => array('Internal error. Height for ActivityTitles is < 0',0), -6002 => array('You can\'t specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.',0), -6003 => array('Invalid format for Constrain parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)',1), -6004 => array('Invalid format for Progress parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)',1), -6005 => array('SetScale() is not meaningful with Gantt charts.',0), -6006 => array('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]',0), -6007 => array('Sanity check for automatic Gantt chart size failed. Either the width (=%d) or height (=%d) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.',2), -6008 => array('You have specified a constrain from row=%d to row=%d which does not have any activity',2), -6009 => array('Unknown constrain type specified from row=%d to row=%d',2), -6010 => array('Illegal icon index for Gantt builtin icon [%d]',1), -6011 => array('Argument to IconImage must be string or integer',0), -6012 => array('Unknown type in Gantt object title specification',0), -6015 => array('Illegal vertical position %d',1), -6016 => array('Date string (%s) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30',1), -6017 => array('Unknown date format in GanttScale (%s).',1), -6018 => array('Interval for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an interval of %d minutes.',1), -6019 => array('The available width (%d) for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.',1), -6020 => array('Interval for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an interval of %d',1), -6021 => array('Unknown formatting style for week.',0), -6022 => array('Gantt scale has not been specified.',0), -6023 => array('If you display both hour and minutes the hour interval must be 1 (Otherwise it doesn\'t make sense to display minutes).',0), -6024 => array('CSIM Target must be specified as a string. Start of target is: %d',1), -6025 => array('CSIM Alt text must be specified as a string. Start of alt text is: %d',1), -6027 => array('Progress value must in range [0, 1]',0), -6028 => array('Specified height (%d) for gantt bar is out of range.',1), -6029 => array('Offset for vertical line must be in range [0,1]',0), -6030 => array('Unknown arrow direction for link.',0), -6031 => array('Unknown arrow type for link.',0), -6032 => array('Internal error: Unknown path type (=%d) specified for link.',1), -6033 => array('Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)',0), - -/* -** jpgraph_gradient -*/ - -7001 => array('Unknown gradient style (=%d).',1), - -/* -** jpgraph_iconplot -*/ - -8001 => array('Mix value for icon must be between 0 and 100.',0), -8002 => array('Anchor position for icons must be one of "top", "bottom", "left", "right" or "center"',0), -8003 => array('It is not possible to specify both an image file and a country flag for the same icon.',0), -8004 => array('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.',0), - -/* -** jpgraph_imgtrans -*/ - -9001 => array('Value for image transformation out of bounds. Vanishing point on horizon must be specified as a value between 0 and 1.',0), - -/* -** jpgraph_lineplot -*/ - -10001 => array('LinePlot::SetFilled() is deprecated. Use SetFillColor()',0), -10002 => array('Plot too complicated for fast line Stroke. Use standard Stroke()',0), -10003 => array('Each plot in an accumulated lineplot must have the same number of data points.',0), - -/* -** jpgraph_log -*/ - -11001 => array('Your data contains non-numeric values.',0), -11002 => array('Negative data values can not be used in a log scale.',0), -11003 => array('Your data contains non-numeric values.',0), -11004 => array('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.',0), -11005 => array('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.',0), - -/* -** jpgraph_mgraph -*/ - -12001 => array("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.",0), -12002 => array('Incorrect file name for MGraph::SetBackgroundImage() : %s Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), -12003 => array('Unknown file extension (%s) in MGraph::SetBackgroundImage() for filename: %s',2), -12004 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), -12005 => array('Can\'t read background image: %s',1), -12006 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), -12007 => array('Argument to MGraph::Add() is not a valid GD image handle.',0), -12008 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats.',0), -12009 => array('Your PHP installation does not support the chosen graphic format: %s',1), -12010 => array('Can\'t create or stream image to file %s Check that PHP has enough permission to write a file to the current directory.',1), -12011 => array('Can\'t create truecolor image. Check that you really have GD2 library installed.',0), -12012 => array('Can\'t create image. Check that you really have GD2 library installed.',0), - -/* -** jpgraph_pie3d -*/ - -14001 => array('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.',0), -14002 => array('PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.',0), -14003 => array('Internal assertion failed. Pie3D::Pie3DSlice',0), -14004 => array('Slice start angle must be between 0 and 360 degrees.',0), -14005 => array('Pie3D Internal error: Trying to wrap twice when looking for start index',0,), -14006 => array('Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.',0), -14007 => array('Width for 3D Pie is 0. Specify a size > 0',0), - -/* -** jpgraph_pie -*/ - -15001 => array('PiePLot::SetTheme() Unknown theme: %s',1), -15002 => array('Argument to PiePlot::ExplodeSlice() must be an integer',0), -15003 => array('Argument to PiePlot::Explode() must be an array with integer distances.',0), -15004 => array('Slice start angle must be between 0 and 360 degrees.',0), -15005 => array('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.',0), -15006 => array('PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]',0), -15007 => array('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.',0), -15008 => array('PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not %d).',1), -15009 => array('Illegal pie plot. Sum of all data is zero for Pie Plot',0), -15010 => array('Sum of all data is 0 for Pie.',0), -15011 => array('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.',0), - -/* -** jpgraph_plotband -*/ - -16001 => array('Density for pattern must be between 1 and 100. (You tried %f)',1), -16002 => array('No positions specified for pattern.',0), -16003 => array('Unknown pattern specification (%d)',0), -16004 => array('Min value for plotband is larger than specified max value. Please correct.',0), - - -/* -** jpgraph_polar -*/ - -17001 => array('Polar plots must have an even number of data point. Each data point is a tuple (angle,radius).',0), -17002 => array('Unknown alignment specified for X-axis title. (%s)',1), -//17003 => array('Set90AndMargin() is not supported for polar graphs.',0), -17004 => array('Unknown scale type for polar graph. Must be "lin" or "log"',0), - -/* -** jpgraph_radar -*/ - -18001 => array('Client side image maps not supported for RadarPlots.',0), -18002 => array('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.',0), -18003 => array('Illegal scale for radarplot (%s). Must be \'lin\' or \'log\'',1), -18004 => array('Radar Plot size must be between 0.1 and 1. (Your value=%f)',1), -18005 => array('RadarPlot Unsupported Tick density: %d',1), -18006 => array('Minimum data %f (Radar plots should only be used when all data points > 0)',1), -18007 => array('Number of titles does not match number of points in plot.',0), -18008 => array('Each radar plot must have the same number of data points.',0), - -/* -** jpgraph_regstat -*/ - -19001 => array('Spline: Number of X and Y coordinates must be the same',0), -19002 => array('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.',0), -19003 => array('Bezier: Number of X and Y coordinates must be the same',0), - -/* -** jpgraph_scatter -*/ - -20001 => array('Fieldplots must have equal number of X and Y points.',0), -20002 => array('Fieldplots must have an angle specified for each X and Y points.',0), -20003 => array('Scatterplot must have equal number of X and Y points.',0), - -/* -** jpgraph_stock -*/ - -21001 => array('Data values for Stock charts must contain an even multiple of %d data points.',1), - -/* -** jpgraph_plotmark -*/ - -23001 => array('This marker "%s" does not exist in color with index: %d',2), -23002 => array('Mark color index too large for marker "%s"',1), -23003 => array('A filename must be specified if you set the mark type to MARK_IMG.',0), - -/* -** jpgraph_utils -*/ - -24001 => array('FuncGenerator : No function specified. ',0), -24002 => array('FuncGenerator : Syntax error in function specification ',0), -24003 => array('DateScaleUtils: Unknown tick type specified in call to GetTicks()',0), -24004 => array('ReadCSV2: Column count mismatch in %s line %d',2), -/* -** jpgraph -*/ - -25001 => array('This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)',0), -25002 => array('Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.',0), -25003 => array('General PHP error : At %s:%d : %s',3), -25004 => array('General PHP error : %s ',1), -25005 => array('Can\'t access PHP_SELF, PHP global variable. You can\'t run PHP from command line if you want to use the \'auto\' naming of cache or image files.',0), -25006 => array('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).',0), -25007 => array('You are trying to use the locale (%s) which your PHP installation does not support. Hint: Use \'\' to indicate the default locale for this geographic region.',1), -25008 => array('Image width/height argument in Graph::Graph() must be numeric',0), -25009 => array('You must specify what scale to use with a call to Graph::SetScale()',0), - -25010 => array('Graph::Add() You tried to add a null plot to the graph.',0), -25011 => array('Graph::AddY2() You tried to add a null plot to the graph.',0), -25012 => array('Graph::AddYN() You tried to add a null plot to the graph.',0), -25013 => array('You can only add standard plots to multiple Y-axis',0), -25014 => array('Graph::AddText() You tried to add a null text to the graph.',0), -25015 => array('Graph::AddLine() You tried to add a null line to the graph.',0), -25016 => array('Graph::AddBand() You tried to add a null band to the graph.',0), -25017 => array('You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.',0), -25018 => array('Incorrect file name for Graph::SetBackgroundImage() : "%s" Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), -25019 => array('Unknown file extension (%s) in Graph::SetBackgroundImage() for filename: "%s"',2), - -25020 => array('Graph::SetScale(): Specified Max value must be larger than the specified Min value.',0), -25021 => array('Unknown scale specification for Y-scale. (%s)',1), -25022 => array('Unknown scale specification for X-scale. (%s)',1), -25023 => array('Unsupported Y2 axis type: "%s" Must be one of (lin,log,int)',1), -25024 => array('Unsupported Y axis type: "%s" Must be one of (lin,log,int)',1), -25025 => array('Unsupported Tick density: %d',1), -25026 => array('Can\'t draw unspecified Y-scale. You have either: 1. Specified an Y axis for auto scaling but have not supplied any plots. 2. Specified a scale manually but have forgot to specify the tick steps',0), -25027 => array('Can\'t open cached CSIM "%s" for reading.',1), -25028 => array('Apache/PHP does not have permission to write to the CSIM cache directory (%s). Check permissions.',1), -25029 => array('Can\'t write CSIM "%s" for writing. Check free space and permissions.',1), - -25030 => array('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().',0), -25031 => array('You must specify what scale to use with a call to Graph::SetScale().',0), -25032 => array('No plots for Y-axis nbr:%d',1), -25033 => array('',0), -25034 => array('Can\'t draw unspecified X-scale. No plots specified.',0), -25035 => array('You have enabled clipping. Clipping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (=%d degrees) or disable clipping.',1), -25036 => array('Unknown AxisStyle() : %s',1), -25037 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), -25038 => array('Background image seems to be of different type (has different file extension) than specified imagetype. Specified: %s File: %s',2), -25039 => array('Can\'t read background image: "%s"',1), - -25040 => array('It is not possible to specify both a background image and a background country flag.',0), -25041 => array('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.',0), -25042 => array('Unknown background image layout',0), -25043 => array('Unknown title background style.',0), -25044 => array('Cannot use auto scaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).',0), -25045 => array('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/',0), -25046 => array('Specified TTF font family (id=%d) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/',1), -25047 => array('Style %s is not available for font family %s',2), -25048 => array('Unknown font style specification [%s].',1), -25049 => array('Font file "%s" is not readable or does not exist.',1), - -25050 => array('First argument to Text::Text() must be a string.',0), -25051 => array('Invalid direction specified for text.',0), -25052 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text',0), -25053 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text',0), -25054 => array('Internal error: Unknown grid axis %s',1), -25055 => array('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead',0), -25056 => array('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.',0), -25057 => array('SetTextTicks() is deprecated. Use SetTextTickInterval() instead.',0), -25058 => array('Text label interval must be specified >= 1.',0), -25059 => array('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.',0), - -25060 => array('Unknown alignment specified for X-axis title. (%s)',1), -25061 => array('Unknown alignment specified for Y-axis title. (%s)',1), -25062 => array('Labels at an angle are not supported on Y-axis',0), -25063 => array('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead',0), -25064 => array('Minor or major step size is 0. Check that you haven\'t got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem',0), -25065 => array('Tick positions must be specified as an array()',0), -25066 => array('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.',0), -25067 => array('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tick marks.',0), -25068 => array('A plot has an illegal scale. This could for example be that you are trying to use text auto scaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only \'-\' or \'x\')',0), -25069 => array('Grace must be larger then 0',0), -25070 => array('Either X or Y data arrays contains non-numeric values. Check that the data is really specified as numeric data and not as strings. It is an error to specify data for example as \'-2345.2\' (using quotes).',0), -25071 => array('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.',0), -25072 => array('You have specified a max value with SetAutoMax() which is smaller than the minimum value used for the scale. This is not possible.',0), -25073 => array('Internal error. Integer scale algorithm comparison out of bound (r=%f)',1), -25074 => array('Internal error. The scale range is negative (%f) [for %s scale] This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the auto scaling to fail.',2), -25075 => array('Can\'t automatically determine ticks since min==max.',0), -25077 => array('Adjustment factor for color must be > 0',0), -25078 => array('Unknown color: %s',1), -25079 => array('Unknown color specification: %s, size=%d',2), - -25080 => array('Alpha parameter for color must be between 0.0 and 1.0',0), -25081 => array('Selected graphic format is either not supported or unknown [%s]',1), -25082 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), -25083 => array('Illegal image size when copying image. Size for copied to image is 1 pixel or less.',0), -25084 => array('Failed to create temporary GD canvas. Possible Out of memory problem.',0), -25085 => array('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.',0), -25086 => array('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to auto detect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.',0), -25087 => array('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.',0), -25088 => array('You have a misconfigured GD font support. The call to imagefontwidth() fails.',0), -25089 => array('You have a misconfigured GD font support. The call to imagefontheight() fails.',0), - -25090 => array('Unknown direction specified in call to StrokeBoxedText() [%s]',1), -25091 => array('Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.',0), -25092 => array('There is either a configuration problem with TrueType or a problem reading font file "%s" Make sure file exists and is in a readable place for the HTTP process. (If \'basedir\' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try upgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library.',1), -25093 => array('Can not read font file "%s" in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.',1), -25094 => array('Direction for text most be given as an angle between 0 and 90.',0), -25095 => array('Unknown font font family specification. ',0), -25096 => array('Can\'t allocate any more colors in palette image. Image has already allocated maximum of %d colors and the palette is now full. Change to a truecolor image instead',0), -25097 => array('Color specified as empty string in PushColor().',0), -25098 => array('Negative Color stack index. Unmatched call to PopColor()',0), -25099 => array('Parameters for brightness and Contrast out of range [-1,1]',0), - -25100 => array('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.',0), -25101 => array('Illegal numeric argument to SetLineStyle(): (%d)',1), -25102 => array('Illegal string argument to SetLineStyle(): %s',1), -25103 => array('Illegal argument to SetLineStyle %s',1), -25104 => array('Unknown line style: %s',1), -25105 => array('NULL data specified for a filled polygon. Check that your data is not NULL.',0), -25106 => array('Image::FillToBorder : Can not allocate more colors',0), -25107 => array('Can\'t write to file "%s". Check that the process running PHP has enough permission.',1), -25108 => array('Can\'t stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP.',0), -25109 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details.',0), - -25110 => array('Your PHP installation does not support the chosen graphic format: %s',1), -25111 => array('Can\'t delete cached image %s. Permission problem?',1), -25112 => array('Cached imagefile (%s) has file date in the future.',1), -25113 => array('Can\'t delete cached image "%s". Permission problem?',1), -25114 => array('PHP has not enough permissions to write to the cache file "%s". Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.',1), -25115 => array('Can\'t set permission for cached image "%s". Permission problem?',1), -25116 => array('Cant open file from cache "%s"',1), -25117 => array('Can\'t open cached image "%s" for reading.',1), -25118 => array('Can\'t create directory "%s". Make sure PHP has write permission to this directory.',1), -25119 => array('Can\'t set permissions for "%s". Permission problems?',1), - -25120 => array('Position for legend must be given as percentage in range 0-1',0), -25121 => array('Empty input data array specified for plot. Must have at least one data point.',0), -25122 => array('Stroke() must be implemented by concrete subclass to class Plot',0), -25123 => array('You can\'t use a text X-scale with specified X-coords. Use a "int" or "lin" scale instead.',0), -25124 => array('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)',0), -25125 => array('Illegal direction for static line',0), -25126 => array('Can\'t create truecolor image. Check that the GD2 library is properly setup with PHP.',0), -25127 => array('The library has been configured for automatic encoding conversion of Japanese fonts. This requires that PHP has the mb_convert_encoding() function. Your PHP installation lacks this function (PHP needs the "--enable-mbstring" when compiled).',0), -25128 => array('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.',0), -25129 => array('Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines.',0), -25130 => array('Too small plot area. (%d x %d). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.',2), - -25131 => array('StrokeBoxedText2() only supports TTF fonts and not built-in bitmap fonts.',0), - -/* -** jpgraph_led -*/ - -25500 => array('Multibyte strings must be enabled in the PHP installation in order to run the LED module so that the function mb_strlen() is available. See PHP documentation for more information.',0), - -/* -**--------------------------------------------------------------------------------------------- -** Pro-version strings -**--------------------------------------------------------------------------------------------- -*/ - -/* -** jpgraph_table -*/ - -27001 => array('GTextTable: Invalid argument to Set(). Array argument must be 2 dimensional',0), -27002 => array('GTextTable: Invalid argument to Set()',0), -27003 => array('GTextTable: Wrong number of arguments to GTextTable::SetColor()',0), -27004 => array('GTextTable: Specified cell range to be merged is not valid.',0), -27005 => array('GTextTable: Cannot merge already merged cells in the range: (%d,%d) to (%d,%d)',4), -27006 => array('GTextTable: Column argument = %d is outside specified table size.',1), -27007 => array('GTextTable: Row argument = %d is outside specified table size.',1), -27008 => array('GTextTable: Column and row size arrays must match the dimensions of the table',0), -27009 => array('GTextTable: Number of table columns or rows are 0. Make sure Init() or Set() is called.',0), -27010 => array('GTextTable: No alignment specified in call to SetAlign()',0), -27011 => array('GTextTable: Unknown alignment specified in SetAlign(). Horizontal=%s, Vertical=%s',2), -27012 => array('GTextTable: Internal error. Invalid alignment specified =%s',1), -27013 => array('GTextTable: Argument to FormatNumber() must be a string.',0), -27014 => array('GTextTable: Table is not initilaized with either a call to Set() or Init()',0), -27015 => array('GTextTable: Cell image constrain type must be TIMG_WIDTH or TIMG_HEIGHT',0), - -/* -** jpgraph_windrose -*/ - -22001 => array('Total percentage for all windrose legs in a windrose plot can not exceed 100%% !\n(Current max is: %d)',1), -22002 => array('Graph is too small to have a scale. Please make the graph larger.',0), -22004 => array('Label specification for windrose directions must have 16 values (one for each compass direction).',0), -22005 => array('Line style for radial lines must be on of ("solid","dotted","dashed","longdashed") ',0), -22006 => array('Illegal windrose type specified.',0), -22007 => array('To few values for the range legend.',0), -22008 => array('Internal error: Trying to plot free Windrose even though type is not a free windrose',0), -22009 => array('You have specified the same direction twice, once with an angle and once with a compass direction (%f degrees)',0), -22010 => array('Direction must either be a numeric value or one of the 16 compass directions',0), -22011 => array('Windrose index must be numeric or direction label. You have specified index=%d',1), -22012 => array('Windrose radial axis specification contains a direction which is not enabled.',0), -22013 => array('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index=%d)',1), -22014 => array('Index for compass direction must be between 0 and 15.',0), -22015 => array('You have specified an undefined Windrose plot type.',0), -22016 => array('Windrose leg index must be numeric or direction label.',0), -22017 => array('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.',0), -22018 => array('You have specified data for the same compass direction twice, once with text and once with index (Index=%d)',1), -22019 => array('Index for direction must be between 0 and 15. You can\'t specify angles for a Regular Windplot, only index and compass directions.',0), -22020 => array('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.',0), -22021 => array('It is only possible to add Text, IconPlot or WindrosePlot to a Windrose Graph',0), -/* -** jpgraph_odometer -*/ - -13001 => array('Unknown needle style (%d).',1), -13002 => array('Value for odometer (%f) is outside specified scale [%f,%f]',3), - -/* -** jpgraph_barcode -*/ - -1001 => array('Unknown encoder specification: %s',1), -1002 => array('Data validation failed. Can\'t encode [%s] using encoding "%s"',2), -1003 => array('Internal encoding error. Trying to encode %s is not possible in Code 128',1), -1004 => array('Internal barcode error. Unknown UPC-E encoding type: %s',1), -1005 => array('Internal error. Can\'t encode character tuple (%s, %s) in Code-128 charset C',2), -1006 => array('Internal encoding error for CODE 128. Trying to encode control character in CHARSET != A',0), -1007 => array('Internal encoding error for CODE 128. Trying to encode DEL in CHARSET != B',0), -1008 => array('Internal encoding error for CODE 128. Trying to encode small letters in CHARSET != B',0), -1009 => array('Encoding using CODE 93 is not yet supported.',0), -1010 => array('Encoding using POSTNET is not yet supported.',0), -1011 => array('Non supported barcode backend for type %s',1), - -/* -** PDF417 -*/ -26000 => array('PDF417: The PDF417 module requires that the PHP installation must support the function bcmod(). This is normally enabled at compile time. See documentation for more information.',0), -26001 => array('PDF417: Number of Columns must be >= 1 and <= 30',0), -26002 => array('PDF417: Error level must be between 0 and 8',0), -26003 => array('PDF417: Invalid format for input data to encode with PDF417',0), -26004 => array('PDF417: Can\'t encode given data with error level %d and %d columns since it results in too many symbols or more than 90 rows.',2), -26005 => array('PDF417: Can\'t open file "%s" for writing',1), -26006 => array('PDF417: Internal error. Data files for PDF417 cluster %d is corrupted.',1), -26007 => array('PDF417: Internal error. GetPattern: Illegal Code Value = %d (row=%d)',2), -26008 => array('PDF417: Internal error. Mode not found in mode list!! mode=%d',1), -26009 => array('PDF417: Encode error: Illegal character. Can\'t encode character with ASCII code=%d',1), -26010 => array('PDF417: Internal error: No input data in decode.',0), -26011 => array('PDF417: Encoding error. Can\'t use numeric encoding on non-numeric data.',0), -26012 => array('PDF417: Internal error. No input data to decode for Binary compressor.',0), -26013 => array('PDF417: Internal error. Checksum error. Coefficient tables corrupted.',0), -26014 => array('PDF417: Internal error. No data to calculate codewords on.',0), -26015 => array('PDF417: Internal error. State transition table entry 0 is NULL. Entry 1 = (%s)',1), -26016 => array('PDF417: Internal error: Unrecognized state transition mode in decode.',0), - -/* -** jpgraph_contour -*/ - -28001 => array('Third argument to Contour must be an array of colors.',0), -28002 => array('Number of colors must equal the number of isobar lines specified',0), -28003 => array('ContourPlot Internal Error: isobarHCrossing: Coloumn index too large (%d)',1), -28004 => array('ContourPlot Internal Error: isobarHCrossing: Row index too large (%d)',1), -28005 => array('ContourPlot Internal Error: isobarVCrossing: Row index too large (%d)',1), -28006 => array('ContourPlot Internal Error: isobarVCrossing: Col index too large (%d)',1), -28007 => array('ContourPlot interpolation factor is too large (>5)',0), - -/* - * jpgraph_matrix and colormap -*/ -29201 => array('Min range value must be less or equal to max range value for colormaps',0), -29202 => array('The distance between min and max value is too small for numerical precision',0), -29203 => array('Number of color quantification level must be at least %d',1), -29204 => array('Number of colors (%d) is invalid for this colormap. It must be a number that can be written as: %d + k*%d',3), -29205 => array('Colormap specification out of range. Must be an integer in range [0,%d]',1), -29206 => array('Invalid object added to MatrixGraph',0), -29207 => array('Empty input data specified for MatrixPlot',0), -29208 => array('Unknown side specifiction for matrix labels "%s"',1), -29209 => array('CSIM Target matrix must be the same size as the data matrix (csim=%d x %d, data=%d x %d)',4), -29210 => array('CSIM Target for matrix labels does not match the number of labels (csim=%d, labels=%d)',2), - -); - -?> +,) +$_jpg_messages = array( + +/* +** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text +*/ +10 => array('
      JpGraph Error: +HTTP headers have already been sent.
      Caused by output from file %s at line %d.
      Explanation:
      HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

      Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

      For example it is a common mistake to leave a blank line before the opening "<?php".

      ',2), + +/* +** Setup errors +*/ +11 => array('No path specified for CACHE_DIR. Please specify CACHE_DIR manually in jpg-config.inc',0), +12 => array('No path specified for TTF_DIR and path can not be determined automatically. Please specify TTF_DIR manually (in jpg-config.inc).',0), +13 => array('The installed PHP version (%s) is not compatible with this release of the library. The library requires at least PHP version %s',2), + + +/* +** jpgraph_bar +*/ + +2001 => array('Number of colors is not the same as the number of patterns in BarPlot::SetPattern()',0), +2002 => array('Unknown pattern specified in call to BarPlot::SetPattern()',0), +2003 => array('Number of X and Y points are not equal. Number of X-points: %d Number of Y-points: %d',2), +2004 => array('All values for a barplot must be numeric. You have specified value nr [%d] == %s',2), +2005 => array('You have specified an empty array for shadow colors in the bar plot.',0), +2006 => array('Unknown position for values on bars : %s',1), +2007 => array('Cannot create GroupBarPlot from empty plot array.',0), +2008 => array('Group bar plot element nbr %d is undefined or empty.',0), +2009 => array('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the GroupBar plot from an array of BarPlot or AccBarPlot objects. (Class = %s)',1), +2010 => array('Cannot create AccBarPlot from empty plot array.',0), +2011 => array('Acc bar plot element nbr %d is undefined or empty.',1), +2012 => array('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects. (Class=%s)',1), +2013 => array('You have specified an empty array for shadow colors in the bar plot.',0), +2014 => array('Number of datapoints for each data set in accbarplot must be the same',0), +2015 => array('Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-coordinates',0), + + +/* +** jpgraph_date +*/ + +3001 => array('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both',0), + +/* +** jpgraph_error +*/ + +4002 => array('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3',0), + +/* +** jpgraph_flags +*/ + +5001 => array('Unknown flag size (%d).',1), +5002 => array('Flag index %s does not exist.',1), +5003 => array('Invalid ordinal number (%d) specified for flag index.',1), +5004 => array('The (partial) country name %s does not have a corresponding flag image. The flag may still exist but under another name, e.g. instead of "usa" try "united states".',1), + + +/* +** jpgraph_gantt +*/ + +6001 => array('Internal error. Height for ActivityTitles is < 0',0), +6002 => array('You can\'t specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.',0), +6003 => array('Invalid format for Constrain parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)',1), +6004 => array('Invalid format for Progress parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)',1), +6005 => array('SetScale() is not meaningful with Gantt charts.',0), +6006 => array('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]',0), +6007 => array('Sanity check for automatic Gantt chart size failed. Either the width (=%d) or height (=%d) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.',2), +6008 => array('You have specified a constrain from row=%d to row=%d which does not have any activity',2), +6009 => array('Unknown constrain type specified from row=%d to row=%d',2), +6010 => array('Illegal icon index for Gantt builtin icon [%d]',1), +6011 => array('Argument to IconImage must be string or integer',0), +6012 => array('Unknown type in Gantt object title specification',0), +6015 => array('Illegal vertical position %d',1), +6016 => array('Date string (%s) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30',1), +6017 => array('Unknown date format in GanttScale (%s).',1), +6018 => array('Interval for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an interval of %d minutes.',1), +6019 => array('The available width (%d) for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.',1), +6020 => array('Interval for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an interval of %d',1), +6021 => array('Unknown formatting style for week.',0), +6022 => array('Gantt scale has not been specified.',0), +6023 => array('If you display both hour and minutes the hour interval must be 1 (Otherwise it doesn\'t make sense to display minutes).',0), +6024 => array('CSIM Target must be specified as a string. Start of target is: %d',1), +6025 => array('CSIM Alt text must be specified as a string. Start of alt text is: %d',1), +6027 => array('Progress value must in range [0, 1]',0), +6028 => array('Specified height (%d) for gantt bar is out of range.',1), +6029 => array('Offset for vertical line must be in range [0,1]',0), +6030 => array('Unknown arrow direction for link.',0), +6031 => array('Unknown arrow type for link.',0), +6032 => array('Internal error: Unknown path type (=%d) specified for link.',1), +6033 => array('Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)',0), + +/* +** jpgraph_gradient +*/ + +7001 => array('Unknown gradient style (=%d).',1), + +/* +** jpgraph_iconplot +*/ + +8001 => array('Mix value for icon must be between 0 and 100.',0), +8002 => array('Anchor position for icons must be one of "top", "bottom", "left", "right" or "center"',0), +8003 => array('It is not possible to specify both an image file and a country flag for the same icon.',0), +8004 => array('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.',0), + +/* +** jpgraph_imgtrans +*/ + +9001 => array('Value for image transformation out of bounds. Vanishing point on horizon must be specified as a value between 0 and 1.',0), + +/* +** jpgraph_lineplot +*/ + +10001 => array('LinePlot::SetFilled() is deprecated. Use SetFillColor()',0), +10002 => array('Plot too complicated for fast line Stroke. Use standard Stroke()',0), +10003 => array('Each plot in an accumulated lineplot must have the same number of data points.',0), + +/* +** jpgraph_log +*/ + +11001 => array('Your data contains non-numeric values.',0), +11002 => array('Negative data values can not be used in a log scale.',0), +11003 => array('Your data contains non-numeric values.',0), +11004 => array('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.',0), +11005 => array('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.',0), + +/* +** jpgraph_mgraph +*/ + +12001 => array("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.",0), +12002 => array('Incorrect file name for MGraph::SetBackgroundImage() : %s Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), +12003 => array('Unknown file extension (%s) in MGraph::SetBackgroundImage() for filename: %s',2), +12004 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), +12005 => array('Can\'t read background image: %s',1), +12006 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), +12007 => array('Argument to MGraph::Add() is not a valid GD image handle.',0), +12008 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats.',0), +12009 => array('Your PHP installation does not support the chosen graphic format: %s',1), +12010 => array('Can\'t create or stream image to file %s Check that PHP has enough permission to write a file to the current directory.',1), +12011 => array('Can\'t create truecolor image. Check that you really have GD2 library installed.',0), +12012 => array('Can\'t create image. Check that you really have GD2 library installed.',0), + +/* +** jpgraph_pie3d +*/ + +14001 => array('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.',0), +14002 => array('PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.',0), +14003 => array('Internal assertion failed. Pie3D::Pie3DSlice',0), +14004 => array('Slice start angle must be between 0 and 360 degrees.',0), +14005 => array('Pie3D Internal error: Trying to wrap twice when looking for start index',0,), +14006 => array('Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.',0), +14007 => array('Width for 3D Pie is 0. Specify a size > 0',0), + +/* +** jpgraph_pie +*/ + +15001 => array('PiePLot::SetTheme() Unknown theme: %s',1), +15002 => array('Argument to PiePlot::ExplodeSlice() must be an integer',0), +15003 => array('Argument to PiePlot::Explode() must be an array with integer distances.',0), +15004 => array('Slice start angle must be between 0 and 360 degrees.',0), +15005 => array('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.',0), +15006 => array('PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]',0), +15007 => array('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.',0), +15008 => array('PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not %d).',1), +15009 => array('Illegal pie plot. Sum of all data is zero for Pie Plot',0), +15010 => array('Sum of all data is 0 for Pie.',0), +15011 => array('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.',0), + +/* +** jpgraph_plotband +*/ + +16001 => array('Density for pattern must be between 1 and 100. (You tried %f)',1), +16002 => array('No positions specified for pattern.',0), +16003 => array('Unknown pattern specification (%d)',0), +16004 => array('Min value for plotband is larger than specified max value. Please correct.',0), + + +/* +** jpgraph_polar +*/ + +17001 => array('Polar plots must have an even number of data point. Each data point is a tuple (angle,radius).',0), +17002 => array('Unknown alignment specified for X-axis title. (%s)',1), +//17003 => array('Set90AndMargin() is not supported for polar graphs.',0), +17004 => array('Unknown scale type for polar graph. Must be "lin" or "log"',0), + +/* +** jpgraph_radar +*/ + +18001 => array('Client side image maps not supported for RadarPlots.',0), +18002 => array('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.',0), +18003 => array('Illegal scale for radarplot (%s). Must be \'lin\' or \'log\'',1), +18004 => array('Radar Plot size must be between 0.1 and 1. (Your value=%f)',1), +18005 => array('RadarPlot Unsupported Tick density: %d',1), +18006 => array('Minimum data %f (Radar plots should only be used when all data points > 0)',1), +18007 => array('Number of titles does not match number of points in plot.',0), +18008 => array('Each radar plot must have the same number of data points.',0), + +/* +** jpgraph_regstat +*/ + +19001 => array('Spline: Number of X and Y coordinates must be the same',0), +19002 => array('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.',0), +19003 => array('Bezier: Number of X and Y coordinates must be the same',0), + +/* +** jpgraph_scatter +*/ + +20001 => array('Fieldplots must have equal number of X and Y points.',0), +20002 => array('Fieldplots must have an angle specified for each X and Y points.',0), +20003 => array('Scatterplot must have equal number of X and Y points.',0), + +/* +** jpgraph_stock +*/ + +21001 => array('Data values for Stock charts must contain an even multiple of %d data points.',1), + +/* +** jpgraph_plotmark +*/ + +23001 => array('This marker "%s" does not exist in color with index: %d',2), +23002 => array('Mark color index too large for marker "%s"',1), +23003 => array('A filename must be specified if you set the mark type to MARK_IMG.',0), + +/* +** jpgraph_utils +*/ + +24001 => array('FuncGenerator : No function specified. ',0), +24002 => array('FuncGenerator : Syntax error in function specification ',0), +24003 => array('DateScaleUtils: Unknown tick type specified in call to GetTicks()',0), +24004 => array('ReadCSV2: Column count mismatch in %s line %d',2), +/* +** jpgraph +*/ + +25001 => array('This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)',0), +25002 => array('Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.',0), +25003 => array('General PHP error : At %s:%d : %s',3), +25004 => array('General PHP error : %s ',1), +25005 => array('Can\'t access PHP_SELF, PHP global variable. You can\'t run PHP from command line if you want to use the \'auto\' naming of cache or image files.',0), +25006 => array('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).',0), +25007 => array('You are trying to use the locale (%s) which your PHP installation does not support. Hint: Use \'\' to indicate the default locale for this geographic region.',1), +25008 => array('Image width/height argument in Graph::Graph() must be numeric',0), +25009 => array('You must specify what scale to use with a call to Graph::SetScale()',0), + +25010 => array('Graph::Add() You tried to add a null plot to the graph.',0), +25011 => array('Graph::AddY2() You tried to add a null plot to the graph.',0), +25012 => array('Graph::AddYN() You tried to add a null plot to the graph.',0), +25013 => array('You can only add standard plots to multiple Y-axis',0), +25014 => array('Graph::AddText() You tried to add a null text to the graph.',0), +25015 => array('Graph::AddLine() You tried to add a null line to the graph.',0), +25016 => array('Graph::AddBand() You tried to add a null band to the graph.',0), +25017 => array('You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.',0), +25018 => array('Incorrect file name for Graph::SetBackgroundImage() : "%s" Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), +25019 => array('Unknown file extension (%s) in Graph::SetBackgroundImage() for filename: "%s"',2), + +25020 => array('Graph::SetScale(): Specified Max value must be larger than the specified Min value.',0), +25021 => array('Unknown scale specification for Y-scale. (%s)',1), +25022 => array('Unknown scale specification for X-scale. (%s)',1), +25023 => array('Unsupported Y2 axis type: "%s" Must be one of (lin,log,int)',1), +25024 => array('Unsupported Y axis type: "%s" Must be one of (lin,log,int)',1), +25025 => array('Unsupported Tick density: %d',1), +25026 => array('Can\'t draw unspecified Y-scale. You have either: 1. Specified an Y axis for auto scaling but have not supplied any plots. 2. Specified a scale manually but have forgot to specify the tick steps',0), +25027 => array('Can\'t open cached CSIM "%s" for reading.',1), +25028 => array('Apache/PHP does not have permission to write to the CSIM cache directory (%s). Check permissions.',1), +25029 => array('Can\'t write CSIM "%s" for writing. Check free space and permissions.',1), + +25030 => array('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().',0), +25031 => array('You must specify what scale to use with a call to Graph::SetScale().',0), +25032 => array('No plots for Y-axis nbr:%d',1), +25033 => array('',0), +25034 => array('Can\'t draw unspecified X-scale. No plots specified.',0), +25035 => array('You have enabled clipping. Clipping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (=%d degrees) or disable clipping.',1), +25036 => array('Unknown AxisStyle() : %s',1), +25037 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), +25038 => array('Background image seems to be of different type (has different file extension) than specified imagetype. Specified: %s File: %s',2), +25039 => array('Can\'t read background image: "%s"',1), + +25040 => array('It is not possible to specify both a background image and a background country flag.',0), +25041 => array('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.',0), +25042 => array('Unknown background image layout',0), +25043 => array('Unknown title background style.',0), +25044 => array('Cannot use auto scaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).',0), +25045 => array('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/',0), +25046 => array('Specified TTF font family (id=%d) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/',1), +25047 => array('Style %s is not available for font family %s',2), +25048 => array('Unknown font style specification [%s].',1), +25049 => array('Font file "%s" is not readable or does not exist.',1), + +25050 => array('First argument to Text::Text() must be a string.',0), +25051 => array('Invalid direction specified for text.',0), +25052 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text',0), +25053 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text',0), +25054 => array('Internal error: Unknown grid axis %s',1), +25055 => array('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead',0), +25056 => array('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.',0), +25057 => array('SetTextTicks() is deprecated. Use SetTextTickInterval() instead.',0), +25058 => array('Text label interval must be specified >= 1.',0), +25059 => array('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.',0), + +25060 => array('Unknown alignment specified for X-axis title. (%s)',1), +25061 => array('Unknown alignment specified for Y-axis title. (%s)',1), +25062 => array('Labels at an angle are not supported on Y-axis',0), +25063 => array('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead',0), +25064 => array('Minor or major step size is 0. Check that you haven\'t got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem',0), +25065 => array('Tick positions must be specified as an array()',0), +25066 => array('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.',0), +25067 => array('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tick marks.',0), +25068 => array('A plot has an illegal scale. This could for example be that you are trying to use text auto scaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only \'-\' or \'x\')',0), +25069 => array('Grace must be larger then 0',0), +25070 => array('Either X or Y data arrays contains non-numeric values. Check that the data is really specified as numeric data and not as strings. It is an error to specify data for example as \'-2345.2\' (using quotes).',0), +25071 => array('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.',0), +25072 => array('You have specified a max value with SetAutoMax() which is smaller than the minimum value used for the scale. This is not possible.',0), +25073 => array('Internal error. Integer scale algorithm comparison out of bound (r=%f)',1), +25074 => array('Internal error. The scale range is negative (%f) [for %s scale] This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the auto scaling to fail.',2), +25075 => array('Can\'t automatically determine ticks since min==max.',0), +25077 => array('Adjustment factor for color must be > 0',0), +25078 => array('Unknown color: %s',1), +25079 => array('Unknown color specification: %s, size=%d',2), + +25080 => array('Alpha parameter for color must be between 0.0 and 1.0',0), +25081 => array('Selected graphic format is either not supported or unknown [%s]',1), +25082 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), +25083 => array('Illegal image size when copying image. Size for copied to image is 1 pixel or less.',0), +25084 => array('Failed to create temporary GD canvas. Possible Out of memory problem.',0), +25085 => array('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.',0), +25086 => array('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to auto detect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.',0), +25087 => array('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.',0), +25088 => array('You have a misconfigured GD font support. The call to imagefontwidth() fails.',0), +25089 => array('You have a misconfigured GD font support. The call to imagefontheight() fails.',0), + +25090 => array('Unknown direction specified in call to StrokeBoxedText() [%s]',1), +25091 => array('Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.',0), +25092 => array('There is either a configuration problem with TrueType or a problem reading font file "%s" Make sure file exists and is in a readable place for the HTTP process. (If \'basedir\' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try upgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library.',1), +25093 => array('Can not read font file "%s" in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.',1), +25094 => array('Direction for text most be given as an angle between 0 and 90.',0), +25095 => array('Unknown font font family specification. ',0), +25096 => array('Can\'t allocate any more colors in palette image. Image has already allocated maximum of %d colors and the palette is now full. Change to a truecolor image instead',0), +25097 => array('Color specified as empty string in PushColor().',0), +25098 => array('Negative Color stack index. Unmatched call to PopColor()',0), +25099 => array('Parameters for brightness and Contrast out of range [-1,1]',0), + +25100 => array('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.',0), +25101 => array('Illegal numeric argument to SetLineStyle(): (%d)',1), +25102 => array('Illegal string argument to SetLineStyle(): %s',1), +25103 => array('Illegal argument to SetLineStyle %s',1), +25104 => array('Unknown line style: %s',1), +25105 => array('NULL data specified for a filled polygon. Check that your data is not NULL.',0), +25106 => array('Image::FillToBorder : Can not allocate more colors',0), +25107 => array('Can\'t write to file "%s". Check that the process running PHP has enough permission.',1), +25108 => array('Can\'t stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP.',0), +25109 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details.',0), + +25110 => array('Your PHP installation does not support the chosen graphic format: %s',1), +25111 => array('Can\'t delete cached image %s. Permission problem?',1), +25112 => array('Cached imagefile (%s) has file date in the future.',1), +25113 => array('Can\'t delete cached image "%s". Permission problem?',1), +25114 => array('PHP has not enough permissions to write to the cache file "%s". Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.',1), +25115 => array('Can\'t set permission for cached image "%s". Permission problem?',1), +25116 => array('Cant open file from cache "%s"',1), +25117 => array('Can\'t open cached image "%s" for reading.',1), +25118 => array('Can\'t create directory "%s". Make sure PHP has write permission to this directory.',1), +25119 => array('Can\'t set permissions for "%s". Permission problems?',1), + +25120 => array('Position for legend must be given as percentage in range 0-1',0), +25121 => array('Empty input data array specified for plot. Must have at least one data point.',0), +25122 => array('Stroke() must be implemented by concrete subclass to class Plot',0), +25123 => array('You can\'t use a text X-scale with specified X-coords. Use a "int" or "lin" scale instead.',0), +25124 => array('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)',0), +25125 => array('Illegal direction for static line',0), +25126 => array('Can\'t create truecolor image. Check that the GD2 library is properly setup with PHP.',0), +25127 => array('The library has been configured for automatic encoding conversion of Japanese fonts. This requires that PHP has the mb_convert_encoding() function. Your PHP installation lacks this function (PHP needs the "--enable-mbstring" when compiled).',0), +25128 => array('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.',0), +25129 => array('Anti-alias can not be used with dashed lines. Please disable anti-alias or use solid lines.',0), +25130 => array('Too small plot area. (%d x %d). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.',2), + +25131 => array('StrokeBoxedText2() only supports TTF fonts and not built-in bitmap fonts.',0), + +/* +** jpgraph_led +*/ + +25500 => array('Multibyte strings must be enabled in the PHP installation in order to run the LED module so that the function mb_strlen() is available. See PHP documentation for more information.',0), + +/* +**--------------------------------------------------------------------------------------------- +** Pro-version strings +**--------------------------------------------------------------------------------------------- +*/ + +/* +** jpgraph_table +*/ + +27001 => array('GTextTable: Invalid argument to Set(). Array argument must be 2 dimensional',0), +27002 => array('GTextTable: Invalid argument to Set()',0), +27003 => array('GTextTable: Wrong number of arguments to GTextTable::SetColor()',0), +27004 => array('GTextTable: Specified cell range to be merged is not valid.',0), +27005 => array('GTextTable: Cannot merge already merged cells in the range: (%d,%d) to (%d,%d)',4), +27006 => array('GTextTable: Column argument = %d is outside specified table size.',1), +27007 => array('GTextTable: Row argument = %d is outside specified table size.',1), +27008 => array('GTextTable: Column and row size arrays must match the dimensions of the table',0), +27009 => array('GTextTable: Number of table columns or rows are 0. Make sure Init() or Set() is called.',0), +27010 => array('GTextTable: No alignment specified in call to SetAlign()',0), +27011 => array('GTextTable: Unknown alignment specified in SetAlign(). Horizontal=%s, Vertical=%s',2), +27012 => array('GTextTable: Internal error. Invalid alignment specified =%s',1), +27013 => array('GTextTable: Argument to FormatNumber() must be a string.',0), +27014 => array('GTextTable: Table is not initilaized with either a call to Set() or Init()',0), +27015 => array('GTextTable: Cell image constrain type must be TIMG_WIDTH or TIMG_HEIGHT',0), + +/* +** jpgraph_windrose +*/ + +22001 => array('Total percentage for all windrose legs in a windrose plot can not exceed 100%% !\n(Current max is: %d)',1), +22002 => array('Graph is too small to have a scale. Please make the graph larger.',0), +22004 => array('Label specification for windrose directions must have 16 values (one for each compass direction).',0), +22005 => array('Line style for radial lines must be on of ("solid","dotted","dashed","longdashed") ',0), +22006 => array('Illegal windrose type specified.',0), +22007 => array('To few values for the range legend.',0), +22008 => array('Internal error: Trying to plot free Windrose even though type is not a free windrose',0), +22009 => array('You have specified the same direction twice, once with an angle and once with a compass direction (%f degrees)',0), +22010 => array('Direction must either be a numeric value or one of the 16 compass directions',0), +22011 => array('Windrose index must be numeric or direction label. You have specified index=%d',1), +22012 => array('Windrose radial axis specification contains a direction which is not enabled.',0), +22013 => array('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index=%d)',1), +22014 => array('Index for compass direction must be between 0 and 15.',0), +22015 => array('You have specified an undefined Windrose plot type.',0), +22016 => array('Windrose leg index must be numeric or direction label.',0), +22017 => array('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.',0), +22018 => array('You have specified data for the same compass direction twice, once with text and once with index (Index=%d)',1), +22019 => array('Index for direction must be between 0 and 15. You can\'t specify angles for a Regular Windplot, only index and compass directions.',0), +22020 => array('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.',0), +22021 => array('It is only possible to add Text, IconPlot or WindrosePlot to a Windrose Graph',0), +/* +** jpgraph_odometer +*/ + +13001 => array('Unknown needle style (%d).',1), +13002 => array('Value for odometer (%f) is outside specified scale [%f,%f]',3), + +/* +** jpgraph_barcode +*/ + +1001 => array('Unknown encoder specification: %s',1), +1002 => array('Data validation failed. Can\'t encode [%s] using encoding "%s"',2), +1003 => array('Internal encoding error. Trying to encode %s is not possible in Code 128',1), +1004 => array('Internal barcode error. Unknown UPC-E encoding type: %s',1), +1005 => array('Internal error. Can\'t encode character tuple (%s, %s) in Code-128 charset C',2), +1006 => array('Internal encoding error for CODE 128. Trying to encode control character in CHARSET != A',0), +1007 => array('Internal encoding error for CODE 128. Trying to encode DEL in CHARSET != B',0), +1008 => array('Internal encoding error for CODE 128. Trying to encode small letters in CHARSET != B',0), +1009 => array('Encoding using CODE 93 is not yet supported.',0), +1010 => array('Encoding using POSTNET is not yet supported.',0), +1011 => array('Non supported barcode backend for type %s',1), + +/* +** PDF417 +*/ +26000 => array('PDF417: The PDF417 module requires that the PHP installation must support the function bcmod(). This is normally enabled at compile time. See documentation for more information.',0), +26001 => array('PDF417: Number of Columns must be >= 1 and <= 30',0), +26002 => array('PDF417: Error level must be between 0 and 8',0), +26003 => array('PDF417: Invalid format for input data to encode with PDF417',0), +26004 => array('PDF417: Can\'t encode given data with error level %d and %d columns since it results in too many symbols or more than 90 rows.',2), +26005 => array('PDF417: Can\'t open file "%s" for writing',1), +26006 => array('PDF417: Internal error. Data files for PDF417 cluster %d is corrupted.',1), +26007 => array('PDF417: Internal error. GetPattern: Illegal Code Value = %d (row=%d)',2), +26008 => array('PDF417: Internal error. Mode not found in mode list!! mode=%d',1), +26009 => array('PDF417: Encode error: Illegal character. Can\'t encode character with ASCII code=%d',1), +26010 => array('PDF417: Internal error: No input data in decode.',0), +26011 => array('PDF417: Encoding error. Can\'t use numeric encoding on non-numeric data.',0), +26012 => array('PDF417: Internal error. No input data to decode for Binary compressor.',0), +26013 => array('PDF417: Internal error. Checksum error. Coefficient tables corrupted.',0), +26014 => array('PDF417: Internal error. No data to calculate codewords on.',0), +26015 => array('PDF417: Internal error. State transition table entry 0 is NULL. Entry 1 = (%s)',1), +26016 => array('PDF417: Internal error: Unrecognized state transition mode in decode.',0), + +/* +** jpgraph_contour +*/ + +28001 => array('Third argument to Contour must be an array of colors.',0), +28002 => array('Number of colors must equal the number of isobar lines specified',0), +28003 => array('ContourPlot Internal Error: isobarHCrossing: Coloumn index too large (%d)',1), +28004 => array('ContourPlot Internal Error: isobarHCrossing: Row index too large (%d)',1), +28005 => array('ContourPlot Internal Error: isobarVCrossing: Row index too large (%d)',1), +28006 => array('ContourPlot Internal Error: isobarVCrossing: Col index too large (%d)',1), +28007 => array('ContourPlot interpolation factor is too large (>5)',0), + +/* + * jpgraph_matrix and colormap +*/ +29201 => array('Min range value must be less or equal to max range value for colormaps',0), +29202 => array('The distance between min and max value is too small for numerical precision',0), +29203 => array('Number of color quantification level must be at least %d',1), +29204 => array('Number of colors (%d) is invalid for this colormap. It must be a number that can be written as: %d + k*%d',3), +29205 => array('Colormap specification out of range. Must be an integer in range [0,%d]',1), +29206 => array('Invalid object added to MatrixGraph',0), +29207 => array('Empty input data specified for MatrixPlot',0), +29208 => array('Unknown side specifiction for matrix labels "%s"',1), +29209 => array('CSIM Target matrix must be the same size as the data matrix (csim=%d x %d, data=%d x %d)',4), +29210 => array('CSIM Target for matrix labels does not match the number of labels (csim=%d, labels=%d)',2), + +); + +?> diff --git a/ext/jpgraph-3.0.7/src/lang/prod.inc.php b/ext/jpgraph-3.0.7/src/lang/prod.inc.php index 8b37647..0c98f22 100644 --- a/ext/jpgraph-3.0.7/src/lang/prod.inc.php +++ b/ext/jpgraph-3.0.7/src/lang/prod.inc.php @@ -1,383 +1,383 @@ -,) -$_jpg_messages = array( - -/* -** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text -*/ -10 => array('
      JpGraph Error: -HTTP headers have already been sent.
      Caused by output from file %s at line %d.
      Explanation:
      HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

      Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

      For example it is a common mistake to leave a blank line before the opening "<?php".

      ',2), - - -11 => array(DEFAULT_ERROR_MESSAGE.'11',0), -12 => array(DEFAULT_ERROR_MESSAGE.'12',0), -13 => array(DEFAULT_ERROR_MESSAGE.'13',0), -2001 => array(DEFAULT_ERROR_MESSAGE.'2001',0), -2002 => array(DEFAULT_ERROR_MESSAGE.'2002',0), -2003 => array(DEFAULT_ERROR_MESSAGE.'2003',0), -2004 => array(DEFAULT_ERROR_MESSAGE.'2004',0), -2005 => array(DEFAULT_ERROR_MESSAGE.'2005',0), -2006 => array(DEFAULT_ERROR_MESSAGE.'2006',0), -2007 => array(DEFAULT_ERROR_MESSAGE.'2007',0), -2008 => array(DEFAULT_ERROR_MESSAGE.'2008',0), -2009 => array(DEFAULT_ERROR_MESSAGE.'2009',0), -2010 => array(DEFAULT_ERROR_MESSAGE.'2010',0), -2011 => array(DEFAULT_ERROR_MESSAGE.'2011',0), -2012 => array(DEFAULT_ERROR_MESSAGE.'2012',0), -2013 => array(DEFAULT_ERROR_MESSAGE.'2013',0), -2014 => array(DEFAULT_ERROR_MESSAGE.'2014',0), -3001 => array(DEFAULT_ERROR_MESSAGE.'3001',0), -4002 => array(DEFAULT_ERROR_MESSAGE.'4002',0), -5001 => array(DEFAULT_ERROR_MESSAGE.'5001',0), -5002 => array(DEFAULT_ERROR_MESSAGE.'5002',0), -5003 => array(DEFAULT_ERROR_MESSAGE.'5003',0), -5004 => array(DEFAULT_ERROR_MESSAGE.'5004',0), -6001 => array(DEFAULT_ERROR_MESSAGE.'6001',0), -6002 => array(DEFAULT_ERROR_MESSAGE.'6002',0), -6003 => array(DEFAULT_ERROR_MESSAGE.'6003',0), -6004 => array(DEFAULT_ERROR_MESSAGE.'6004',0), -6005 => array(DEFAULT_ERROR_MESSAGE.'6005',0), -6006 => array(DEFAULT_ERROR_MESSAGE.'6006',0), -6007 => array(DEFAULT_ERROR_MESSAGE.'6007',0), -6008 => array(DEFAULT_ERROR_MESSAGE.'6008',0), -6009 => array(DEFAULT_ERROR_MESSAGE.'6009',0), -6010 => array(DEFAULT_ERROR_MESSAGE.'6010',0), -6011 => array(DEFAULT_ERROR_MESSAGE.'6011',0), -6012 => array(DEFAULT_ERROR_MESSAGE.'6012',0), -6015 => array(DEFAULT_ERROR_MESSAGE.'6015',0), -6016 => array(DEFAULT_ERROR_MESSAGE.'6016',0), -6017 => array(DEFAULT_ERROR_MESSAGE.'6017',0), -6018 => array(DEFAULT_ERROR_MESSAGE.'6018',0), -6019 => array(DEFAULT_ERROR_MESSAGE.'6019',0), -6020 => array(DEFAULT_ERROR_MESSAGE.'6020',0), -6021 => array(DEFAULT_ERROR_MESSAGE.'6021',0), -6022 => array(DEFAULT_ERROR_MESSAGE.'6022',0), -6023 => array(DEFAULT_ERROR_MESSAGE.'6023',0), -6024 => array(DEFAULT_ERROR_MESSAGE.'6024',0), -6025 => array(DEFAULT_ERROR_MESSAGE.'6025',0), -6027 => array(DEFAULT_ERROR_MESSAGE.'6027',0), -6028 => array(DEFAULT_ERROR_MESSAGE.'6028',0), -6029 => array(DEFAULT_ERROR_MESSAGE.'6029',0), -6030 => array(DEFAULT_ERROR_MESSAGE.'6030',0), -6031 => array(DEFAULT_ERROR_MESSAGE.'6031',0), -6032 => array(DEFAULT_ERROR_MESSAGE.'6032',0), -6033 => array(DEFAULT_ERROR_MESSAGE.'6033',0), -7001 => array(DEFAULT_ERROR_MESSAGE.'7001',0), -8001 => array(DEFAULT_ERROR_MESSAGE.'8001',0), -8002 => array(DEFAULT_ERROR_MESSAGE.'8002',0), -8003 => array(DEFAULT_ERROR_MESSAGE.'8003',0), -8004 => array(DEFAULT_ERROR_MESSAGE.'8004',0), -9001 => array(DEFAULT_ERROR_MESSAGE.'9001',0), -10001 => array(DEFAULT_ERROR_MESSAGE.'10001',0), -10002 => array(DEFAULT_ERROR_MESSAGE.'10002',0), -10003 => array(DEFAULT_ERROR_MESSAGE.'10003',0), -11001 => array(DEFAULT_ERROR_MESSAGE.'11001',0), -11002 => array(DEFAULT_ERROR_MESSAGE.'11002',0), -11003 => array(DEFAULT_ERROR_MESSAGE.'11003',0), -11004 => array(DEFAULT_ERROR_MESSAGE.'11004',0), -11005 => array(DEFAULT_ERROR_MESSAGE.'11005',0), -12001 => array(DEFAULT_ERROR_MESSAGE.'12001',0), -12002 => array(DEFAULT_ERROR_MESSAGE.'12002',0), -12003 => array(DEFAULT_ERROR_MESSAGE.'12003',0), -12004 => array(DEFAULT_ERROR_MESSAGE.'12004',0), -12005 => array(DEFAULT_ERROR_MESSAGE.'12005',0), -12006 => array(DEFAULT_ERROR_MESSAGE.'12006',0), -12007 => array(DEFAULT_ERROR_MESSAGE.'12007',0), -12008 => array(DEFAULT_ERROR_MESSAGE.'12008',0), -12009 => array(DEFAULT_ERROR_MESSAGE.'12009',0), -12010 => array(DEFAULT_ERROR_MESSAGE.'12010',0), -12011 => array(DEFAULT_ERROR_MESSAGE.'12011',0), -12012 => array(DEFAULT_ERROR_MESSAGE.'12012',0), -14001 => array(DEFAULT_ERROR_MESSAGE.'14001',0), -14002 => array(DEFAULT_ERROR_MESSAGE.'14002',0), -14003 => array(DEFAULT_ERROR_MESSAGE.'14003',0), -14004 => array(DEFAULT_ERROR_MESSAGE.'14004',0), -14005 => array(DEFAULT_ERROR_MESSAGE.'14005',0), -14006 => array(DEFAULT_ERROR_MESSAGE.'14006',0), -14007 => array(DEFAULT_ERROR_MESSAGE.'14007',0), -15001 => array(DEFAULT_ERROR_MESSAGE.'15001',0), -15002 => array(DEFAULT_ERROR_MESSAGE.'15002',0), -15003 => array(DEFAULT_ERROR_MESSAGE.'15003',0), -15004 => array(DEFAULT_ERROR_MESSAGE.'15004',0), -15005 => array(DEFAULT_ERROR_MESSAGE.'15005',0), -15006 => array(DEFAULT_ERROR_MESSAGE.'15006',0), -15007 => array(DEFAULT_ERROR_MESSAGE.'15007',0), -15008 => array(DEFAULT_ERROR_MESSAGE.'15008',0), -15009 => array(DEFAULT_ERROR_MESSAGE.'15009',0), -15010 => array(DEFAULT_ERROR_MESSAGE.'15010',0), -15011 => array(DEFAULT_ERROR_MESSAGE.'15011',0), -16001 => array(DEFAULT_ERROR_MESSAGE.'16001',0), -16002 => array(DEFAULT_ERROR_MESSAGE.'16002',0), -16003 => array(DEFAULT_ERROR_MESSAGE.'16003',0), -16004 => array(DEFAULT_ERROR_MESSAGE.'16004',0), -17001 => array(DEFAULT_ERROR_MESSAGE.'17001',0), -17002 => array(DEFAULT_ERROR_MESSAGE.'17002',0), -17004 => array(DEFAULT_ERROR_MESSAGE.'17004',0), -18001 => array(DEFAULT_ERROR_MESSAGE.'18001',0), -18002 => array(DEFAULT_ERROR_MESSAGE.'18002',0), -18003 => array(DEFAULT_ERROR_MESSAGE.'18003',0), -18004 => array(DEFAULT_ERROR_MESSAGE.'18004',0), -18005 => array(DEFAULT_ERROR_MESSAGE.'18005',0), -18006 => array(DEFAULT_ERROR_MESSAGE.'18006',0), -18007 => array(DEFAULT_ERROR_MESSAGE.'18007',0), -18008 => array(DEFAULT_ERROR_MESSAGE.'18008',0), -19001 => array(DEFAULT_ERROR_MESSAGE.'19001',0), -19002 => array(DEFAULT_ERROR_MESSAGE.'19002',0), -19003 => array(DEFAULT_ERROR_MESSAGE.'19003',0), -20001 => array(DEFAULT_ERROR_MESSAGE.'20001',0), -20002 => array(DEFAULT_ERROR_MESSAGE.'20002',0), -20003 => array(DEFAULT_ERROR_MESSAGE.'20003',0), -21001 => array(DEFAULT_ERROR_MESSAGE.'21001',0), -23001 => array(DEFAULT_ERROR_MESSAGE.'23001',0), -23002 => array(DEFAULT_ERROR_MESSAGE.'23002',0), -23003 => array(DEFAULT_ERROR_MESSAGE.'23003',0), -24001 => array(DEFAULT_ERROR_MESSAGE.'24001',0), -24002 => array(DEFAULT_ERROR_MESSAGE.'24002',0), -24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), -24004 => array(DEFAULT_ERROR_MESSAGE.'24004',0), -25001 => array(DEFAULT_ERROR_MESSAGE.'25001',0), -25002 => array(DEFAULT_ERROR_MESSAGE.'25002',0), -25003 => array(DEFAULT_ERROR_MESSAGE.'25003',0), -25004 => array(DEFAULT_ERROR_MESSAGE.'25004',0), -25005 => array(DEFAULT_ERROR_MESSAGE.'25005',0), -25006 => array(DEFAULT_ERROR_MESSAGE.'25006',0), -25007 => array(DEFAULT_ERROR_MESSAGE.'25007',0), -25008 => array(DEFAULT_ERROR_MESSAGE.'25008',0), -25009 => array(DEFAULT_ERROR_MESSAGE.'25009',0), -25010 => array(DEFAULT_ERROR_MESSAGE.'25010',0), -25011 => array(DEFAULT_ERROR_MESSAGE.'25011',0), -25012 => array(DEFAULT_ERROR_MESSAGE.'25012',0), -25013 => array(DEFAULT_ERROR_MESSAGE.'25013',0), -25014 => array(DEFAULT_ERROR_MESSAGE.'25014',0), -25015 => array(DEFAULT_ERROR_MESSAGE.'25015',0), -25016 => array(DEFAULT_ERROR_MESSAGE.'25016',0), -25017 => array(DEFAULT_ERROR_MESSAGE.'25017',0), -25018 => array(DEFAULT_ERROR_MESSAGE.'25018',0), -25019 => array(DEFAULT_ERROR_MESSAGE.'25019',0), -25020 => array(DEFAULT_ERROR_MESSAGE.'25020',0), -25021 => array(DEFAULT_ERROR_MESSAGE.'25021',0), -25022 => array(DEFAULT_ERROR_MESSAGE.'25022',0), -25023 => array(DEFAULT_ERROR_MESSAGE.'25023',0), -25024 => array(DEFAULT_ERROR_MESSAGE.'25024',0), -25025 => array(DEFAULT_ERROR_MESSAGE.'25025',0), -25026 => array(DEFAULT_ERROR_MESSAGE.'25026',0), -25027 => array(DEFAULT_ERROR_MESSAGE.'25027',0), -25028 => array(DEFAULT_ERROR_MESSAGE.'25028',0), -25029 => array(DEFAULT_ERROR_MESSAGE.'25029',0), -25030 => array(DEFAULT_ERROR_MESSAGE.'25030',0), -25031 => array(DEFAULT_ERROR_MESSAGE.'25031',0), -25032 => array(DEFAULT_ERROR_MESSAGE.'25032',0), -25033 => array(DEFAULT_ERROR_MESSAGE.'25033',0), -25034 => array(DEFAULT_ERROR_MESSAGE.'25034',0), -25035 => array(DEFAULT_ERROR_MESSAGE.'25035',0), -25036 => array(DEFAULT_ERROR_MESSAGE.'25036',0), -25037 => array(DEFAULT_ERROR_MESSAGE.'25037',0), -25038 => array(DEFAULT_ERROR_MESSAGE.'25038',0), -25039 => array(DEFAULT_ERROR_MESSAGE.'25039',0), -25040 => array(DEFAULT_ERROR_MESSAGE.'25040',0), -25041 => array(DEFAULT_ERROR_MESSAGE.'25041',0), -25042 => array(DEFAULT_ERROR_MESSAGE.'25042',0), -25043 => array(DEFAULT_ERROR_MESSAGE.'25043',0), -25044 => array(DEFAULT_ERROR_MESSAGE.'25044',0), -25045 => array(DEFAULT_ERROR_MESSAGE.'25045',0), -25046 => array(DEFAULT_ERROR_MESSAGE.'25046',0), -25047 => array(DEFAULT_ERROR_MESSAGE.'25047',0), -25048 => array(DEFAULT_ERROR_MESSAGE.'25048',0), -25049 => array(DEFAULT_ERROR_MESSAGE.'25049',0), -25050 => array(DEFAULT_ERROR_MESSAGE.'25050',0), -25051 => array(DEFAULT_ERROR_MESSAGE.'25051',0), -25052 => array(DEFAULT_ERROR_MESSAGE.'25052',0), -25053 => array(DEFAULT_ERROR_MESSAGE.'25053',0), -25054 => array(DEFAULT_ERROR_MESSAGE.'25054',0), -25055 => array(DEFAULT_ERROR_MESSAGE.'25055',0), -25056 => array(DEFAULT_ERROR_MESSAGE.'25056',0), -25057 => array(DEFAULT_ERROR_MESSAGE.'25057',0), -25058 => array(DEFAULT_ERROR_MESSAGE.'25058',0), -25059 => array(DEFAULT_ERROR_MESSAGE.'25059',0), -25060 => array(DEFAULT_ERROR_MESSAGE.'25060',0), -25061 => array(DEFAULT_ERROR_MESSAGE.'25061',0), -25062 => array(DEFAULT_ERROR_MESSAGE.'25062',0), -25063 => array(DEFAULT_ERROR_MESSAGE.'25063',0), -25064 => array(DEFAULT_ERROR_MESSAGE.'25064',0), -25065 => array(DEFAULT_ERROR_MESSAGE.'25065',0), -25066 => array(DEFAULT_ERROR_MESSAGE.'25066',0), -25067 => array(DEFAULT_ERROR_MESSAGE.'25067',0), -25068 => array(DEFAULT_ERROR_MESSAGE.'25068',0), -25069 => array(DEFAULT_ERROR_MESSAGE.'25069',0), -25070 => array(DEFAULT_ERROR_MESSAGE.'25070',0), -25071 => array(DEFAULT_ERROR_MESSAGE.'25071',0), -25072 => array(DEFAULT_ERROR_MESSAGE.'25072',0), -25073 => array(DEFAULT_ERROR_MESSAGE.'25073',0), -25074 => array(DEFAULT_ERROR_MESSAGE.'25074',0), -25075 => array(DEFAULT_ERROR_MESSAGE.'25075',0), -25077 => array(DEFAULT_ERROR_MESSAGE.'25077',0), -25078 => array(DEFAULT_ERROR_MESSAGE.'25078',0), -25079 => array(DEFAULT_ERROR_MESSAGE.'25079',0), -25080 => array(DEFAULT_ERROR_MESSAGE.'25080',0), -25081 => array(DEFAULT_ERROR_MESSAGE.'25081',0), -25082 => array(DEFAULT_ERROR_MESSAGE.'25082',0), -25083 => array(DEFAULT_ERROR_MESSAGE.'25083',0), -25084 => array(DEFAULT_ERROR_MESSAGE.'25084',0), -25085 => array(DEFAULT_ERROR_MESSAGE.'25085',0), -25086 => array(DEFAULT_ERROR_MESSAGE.'25086',0), -25087 => array(DEFAULT_ERROR_MESSAGE.'25087',0), -25088 => array(DEFAULT_ERROR_MESSAGE.'25088',0), -25089 => array(DEFAULT_ERROR_MESSAGE.'25089',0), -25090 => array(DEFAULT_ERROR_MESSAGE.'25090',0), -25091 => array(DEFAULT_ERROR_MESSAGE.'25091',0), -25092 => array(DEFAULT_ERROR_MESSAGE.'25092',0), -25093 => array(DEFAULT_ERROR_MESSAGE.'25093',0), -25094 => array(DEFAULT_ERROR_MESSAGE.'25094',0), -25095 => array(DEFAULT_ERROR_MESSAGE.'25095',0), -25096 => array(DEFAULT_ERROR_MESSAGE.'25096',0), -25097 => array(DEFAULT_ERROR_MESSAGE.'25097',0), -25098 => array(DEFAULT_ERROR_MESSAGE.'25098',0), -25099 => array(DEFAULT_ERROR_MESSAGE.'25099',0), -25100 => array(DEFAULT_ERROR_MESSAGE.'25100',0), -25101 => array(DEFAULT_ERROR_MESSAGE.'25101',0), -25102 => array(DEFAULT_ERROR_MESSAGE.'25102',0), -25103 => array(DEFAULT_ERROR_MESSAGE.'25103',0), -25104 => array(DEFAULT_ERROR_MESSAGE.'25104',0), -25105 => array(DEFAULT_ERROR_MESSAGE.'25105',0), -25106 => array(DEFAULT_ERROR_MESSAGE.'25106',0), -25107 => array(DEFAULT_ERROR_MESSAGE.'25107',0), -25108 => array(DEFAULT_ERROR_MESSAGE.'25108',0), -25109 => array(DEFAULT_ERROR_MESSAGE.'25109',0), -25110 => array(DEFAULT_ERROR_MESSAGE.'25110',0), -25111 => array(DEFAULT_ERROR_MESSAGE.'25111',0), -25112 => array(DEFAULT_ERROR_MESSAGE.'25112',0), -25113 => array(DEFAULT_ERROR_MESSAGE.'25113',0), -25114 => array(DEFAULT_ERROR_MESSAGE.'25114',0), -25115 => array(DEFAULT_ERROR_MESSAGE.'25115',0), -25116 => array(DEFAULT_ERROR_MESSAGE.'25116',0), -25117 => array(DEFAULT_ERROR_MESSAGE.'25117',0), -25118 => array(DEFAULT_ERROR_MESSAGE.'25118',0), -25119 => array(DEFAULT_ERROR_MESSAGE.'25119',0), -25120 => array(DEFAULT_ERROR_MESSAGE.'25120',0), -25121 => array(DEFAULT_ERROR_MESSAGE.'25121',0), -25122 => array(DEFAULT_ERROR_MESSAGE.'25122',0), -25123 => array(DEFAULT_ERROR_MESSAGE.'25123',0), -25124 => array(DEFAULT_ERROR_MESSAGE.'25124',0), -25125 => array(DEFAULT_ERROR_MESSAGE.'25125',0), -25126 => array(DEFAULT_ERROR_MESSAGE.'25126',0), -25127 => array(DEFAULT_ERROR_MESSAGE.'25127',0), -25128 => array(DEFAULT_ERROR_MESSAGE.'25128',0), -25129 => array(DEFAULT_ERROR_MESSAGE.'25129',0), -25130 => array(DEFAULT_ERROR_MESSAGE.'25130',0), -25131 => array(DEFAULT_ERROR_MESSAGE.'25131',0), -25500 => array(DEFAULT_ERROR_MESSAGE.'25500',0), -24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), -24004 => array(DEFAULT_ERROR_MESSAGE.'24004',0), -24005 => array(DEFAULT_ERROR_MESSAGE.'24005',0), -24006 => array(DEFAULT_ERROR_MESSAGE.'24006',0), -24007 => array(DEFAULT_ERROR_MESSAGE.'24007',0), -24008 => array(DEFAULT_ERROR_MESSAGE.'24008',0), -24009 => array(DEFAULT_ERROR_MESSAGE.'24009',0), -24010 => array(DEFAULT_ERROR_MESSAGE.'24010',0), -24011 => array(DEFAULT_ERROR_MESSAGE.'24011',0), -24012 => array(DEFAULT_ERROR_MESSAGE.'24012',0), -24013 => array(DEFAULT_ERROR_MESSAGE.'24013',0), -24014 => array(DEFAULT_ERROR_MESSAGE.'24014',0), -24015 => array(DEFAULT_ERROR_MESSAGE.'24015',0), -22001 => array(DEFAULT_ERROR_MESSAGE.'22001',0), -22002 => array(DEFAULT_ERROR_MESSAGE.'22002',0), -22004 => array(DEFAULT_ERROR_MESSAGE.'22004',0), -22005 => array(DEFAULT_ERROR_MESSAGE.'22005',0), -22006 => array(DEFAULT_ERROR_MESSAGE.'22006',0), -22007 => array(DEFAULT_ERROR_MESSAGE.'22007',0), -22008 => array(DEFAULT_ERROR_MESSAGE.'22008',0), -22009 => array(DEFAULT_ERROR_MESSAGE.'22009',0), -22010 => array(DEFAULT_ERROR_MESSAGE.'22010',0), -22011 => array(DEFAULT_ERROR_MESSAGE.'22011',0), -22012 => array(DEFAULT_ERROR_MESSAGE.'22012',0), -22013 => array(DEFAULT_ERROR_MESSAGE.'22013',0), -22014 => array(DEFAULT_ERROR_MESSAGE.'22014',0), -22015 => array(DEFAULT_ERROR_MESSAGE.'22015',0), -22016 => array(DEFAULT_ERROR_MESSAGE.'22016',0), -22017 => array(DEFAULT_ERROR_MESSAGE.'22017',0), -22018 => array(DEFAULT_ERROR_MESSAGE.'22018',0), -22019 => array(DEFAULT_ERROR_MESSAGE.'22019',0), -22020 => array(DEFAULT_ERROR_MESSAGE.'22020',0), -13001 => array(DEFAULT_ERROR_MESSAGE.'13001',0), -13002 => array(DEFAULT_ERROR_MESSAGE.'13002',0), -1001 => array(DEFAULT_ERROR_MESSAGE.'1001',0), -1002 => array(DEFAULT_ERROR_MESSAGE.'1002',0), -1003 => array(DEFAULT_ERROR_MESSAGE.'1003',0), -1004 => array(DEFAULT_ERROR_MESSAGE.'1004',0), -1005 => array(DEFAULT_ERROR_MESSAGE.'1005',0), -1006 => array(DEFAULT_ERROR_MESSAGE.'1006',0), -1007 => array(DEFAULT_ERROR_MESSAGE.'1007',0), -1008 => array(DEFAULT_ERROR_MESSAGE.'1008',0), -1009 => array(DEFAULT_ERROR_MESSAGE.'1009',0), -1010 => array(DEFAULT_ERROR_MESSAGE.'1010',0), -1011 => array(DEFAULT_ERROR_MESSAGE.'1011',0), -26000 => array(DEFAULT_ERROR_MESSAGE.'26000',0), -26001 => array(DEFAULT_ERROR_MESSAGE.'26001',0), -26002 => array(DEFAULT_ERROR_MESSAGE.'26002',0), -26003 => array(DEFAULT_ERROR_MESSAGE.'26003',0), -26004 => array(DEFAULT_ERROR_MESSAGE.'26004',0), -26005 => array(DEFAULT_ERROR_MESSAGE.'26005',0), -26006 => array(DEFAULT_ERROR_MESSAGE.'26006',0), -26007 => array(DEFAULT_ERROR_MESSAGE.'26007',0), -26008 => array(DEFAULT_ERROR_MESSAGE.'26008',0), -26009 => array(DEFAULT_ERROR_MESSAGE.'26009',0), -26010 => array(DEFAULT_ERROR_MESSAGE.'26010',0), -26011 => array(DEFAULT_ERROR_MESSAGE.'26011',0), -26012 => array(DEFAULT_ERROR_MESSAGE.'26012',0), -26013 => array(DEFAULT_ERROR_MESSAGE.'26013',0), -26014 => array(DEFAULT_ERROR_MESSAGE.'26014',0), -26015 => array(DEFAULT_ERROR_MESSAGE.'26015',0), -26016 => array(DEFAULT_ERROR_MESSAGE.'26016',0), - -27001 => array(DEFAULT_ERROR_MESSAGE.'27001',0), -27002 => array(DEFAULT_ERROR_MESSAGE.'27002',0), -27003 => array(DEFAULT_ERROR_MESSAGE.'27003',0), -27004 => array(DEFAULT_ERROR_MESSAGE.'27004',0), -27005 => array(DEFAULT_ERROR_MESSAGE.'27005',0), -27006 => array(DEFAULT_ERROR_MESSAGE.'27006',0), -27007 => array(DEFAULT_ERROR_MESSAGE.'27007',0), -27008 => array(DEFAULT_ERROR_MESSAGE.'27008',0), -27009 => array(DEFAULT_ERROR_MESSAGE.'27009',0), -27010 => array(DEFAULT_ERROR_MESSAGE.'27010',0), -27011 => array(DEFAULT_ERROR_MESSAGE.'27011',0), -27012 => array(DEFAULT_ERROR_MESSAGE.'27012',0), -27013 => array(DEFAULT_ERROR_MESSAGE.'27013',0), -27014 => array(DEFAULT_ERROR_MESSAGE.'27014',0), -27015 => array(DEFAULT_ERROR_MESSAGE.'27015',0), - -28001 => array(DEFAULT_ERROR_MESSAGE.'28001',0), -28002 => array(DEFAULT_ERROR_MESSAGE.'28002',0), -28003 => array(DEFAULT_ERROR_MESSAGE.'28003',0), -28004 => array(DEFAULT_ERROR_MESSAGE.'28004',0), -28005 => array(DEFAULT_ERROR_MESSAGE.'28005',0), -28006 => array(DEFAULT_ERROR_MESSAGE.'28006',0), -28007 => array(DEFAULT_ERROR_MESSAGE.'28007',0), - -29201 => array(DEFAULT_ERROR_MESSAGE.'28001',0), -29202 => array(DEFAULT_ERROR_MESSAGE.'28002',0), -29203 => array(DEFAULT_ERROR_MESSAGE.'28003',0), -29204 => array(DEFAULT_ERROR_MESSAGE.'28004',0), -29205 => array(DEFAULT_ERROR_MESSAGE.'28005',0), -29206 => array(DEFAULT_ERROR_MESSAGE.'28006',0), -29207 => array(DEFAULT_ERROR_MESSAGE.'28007',0), -29208 => array(DEFAULT_ERROR_MESSAGE.'28008',0), -29209 => array(DEFAULT_ERROR_MESSAGE.'28009',0), -29210 => array(DEFAULT_ERROR_MESSAGE.'28010',0), - -); - -?> +,) +$_jpg_messages = array( + +/* +** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text +*/ +10 => array('
      JpGraph Error: +HTTP headers have already been sent.
      Caused by output from file %s at line %d.
      Explanation:
      HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

      Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

      For example it is a common mistake to leave a blank line before the opening "<?php".

      ',2), + + +11 => array(DEFAULT_ERROR_MESSAGE.'11',0), +12 => array(DEFAULT_ERROR_MESSAGE.'12',0), +13 => array(DEFAULT_ERROR_MESSAGE.'13',0), +2001 => array(DEFAULT_ERROR_MESSAGE.'2001',0), +2002 => array(DEFAULT_ERROR_MESSAGE.'2002',0), +2003 => array(DEFAULT_ERROR_MESSAGE.'2003',0), +2004 => array(DEFAULT_ERROR_MESSAGE.'2004',0), +2005 => array(DEFAULT_ERROR_MESSAGE.'2005',0), +2006 => array(DEFAULT_ERROR_MESSAGE.'2006',0), +2007 => array(DEFAULT_ERROR_MESSAGE.'2007',0), +2008 => array(DEFAULT_ERROR_MESSAGE.'2008',0), +2009 => array(DEFAULT_ERROR_MESSAGE.'2009',0), +2010 => array(DEFAULT_ERROR_MESSAGE.'2010',0), +2011 => array(DEFAULT_ERROR_MESSAGE.'2011',0), +2012 => array(DEFAULT_ERROR_MESSAGE.'2012',0), +2013 => array(DEFAULT_ERROR_MESSAGE.'2013',0), +2014 => array(DEFAULT_ERROR_MESSAGE.'2014',0), +3001 => array(DEFAULT_ERROR_MESSAGE.'3001',0), +4002 => array(DEFAULT_ERROR_MESSAGE.'4002',0), +5001 => array(DEFAULT_ERROR_MESSAGE.'5001',0), +5002 => array(DEFAULT_ERROR_MESSAGE.'5002',0), +5003 => array(DEFAULT_ERROR_MESSAGE.'5003',0), +5004 => array(DEFAULT_ERROR_MESSAGE.'5004',0), +6001 => array(DEFAULT_ERROR_MESSAGE.'6001',0), +6002 => array(DEFAULT_ERROR_MESSAGE.'6002',0), +6003 => array(DEFAULT_ERROR_MESSAGE.'6003',0), +6004 => array(DEFAULT_ERROR_MESSAGE.'6004',0), +6005 => array(DEFAULT_ERROR_MESSAGE.'6005',0), +6006 => array(DEFAULT_ERROR_MESSAGE.'6006',0), +6007 => array(DEFAULT_ERROR_MESSAGE.'6007',0), +6008 => array(DEFAULT_ERROR_MESSAGE.'6008',0), +6009 => array(DEFAULT_ERROR_MESSAGE.'6009',0), +6010 => array(DEFAULT_ERROR_MESSAGE.'6010',0), +6011 => array(DEFAULT_ERROR_MESSAGE.'6011',0), +6012 => array(DEFAULT_ERROR_MESSAGE.'6012',0), +6015 => array(DEFAULT_ERROR_MESSAGE.'6015',0), +6016 => array(DEFAULT_ERROR_MESSAGE.'6016',0), +6017 => array(DEFAULT_ERROR_MESSAGE.'6017',0), +6018 => array(DEFAULT_ERROR_MESSAGE.'6018',0), +6019 => array(DEFAULT_ERROR_MESSAGE.'6019',0), +6020 => array(DEFAULT_ERROR_MESSAGE.'6020',0), +6021 => array(DEFAULT_ERROR_MESSAGE.'6021',0), +6022 => array(DEFAULT_ERROR_MESSAGE.'6022',0), +6023 => array(DEFAULT_ERROR_MESSAGE.'6023',0), +6024 => array(DEFAULT_ERROR_MESSAGE.'6024',0), +6025 => array(DEFAULT_ERROR_MESSAGE.'6025',0), +6027 => array(DEFAULT_ERROR_MESSAGE.'6027',0), +6028 => array(DEFAULT_ERROR_MESSAGE.'6028',0), +6029 => array(DEFAULT_ERROR_MESSAGE.'6029',0), +6030 => array(DEFAULT_ERROR_MESSAGE.'6030',0), +6031 => array(DEFAULT_ERROR_MESSAGE.'6031',0), +6032 => array(DEFAULT_ERROR_MESSAGE.'6032',0), +6033 => array(DEFAULT_ERROR_MESSAGE.'6033',0), +7001 => array(DEFAULT_ERROR_MESSAGE.'7001',0), +8001 => array(DEFAULT_ERROR_MESSAGE.'8001',0), +8002 => array(DEFAULT_ERROR_MESSAGE.'8002',0), +8003 => array(DEFAULT_ERROR_MESSAGE.'8003',0), +8004 => array(DEFAULT_ERROR_MESSAGE.'8004',0), +9001 => array(DEFAULT_ERROR_MESSAGE.'9001',0), +10001 => array(DEFAULT_ERROR_MESSAGE.'10001',0), +10002 => array(DEFAULT_ERROR_MESSAGE.'10002',0), +10003 => array(DEFAULT_ERROR_MESSAGE.'10003',0), +11001 => array(DEFAULT_ERROR_MESSAGE.'11001',0), +11002 => array(DEFAULT_ERROR_MESSAGE.'11002',0), +11003 => array(DEFAULT_ERROR_MESSAGE.'11003',0), +11004 => array(DEFAULT_ERROR_MESSAGE.'11004',0), +11005 => array(DEFAULT_ERROR_MESSAGE.'11005',0), +12001 => array(DEFAULT_ERROR_MESSAGE.'12001',0), +12002 => array(DEFAULT_ERROR_MESSAGE.'12002',0), +12003 => array(DEFAULT_ERROR_MESSAGE.'12003',0), +12004 => array(DEFAULT_ERROR_MESSAGE.'12004',0), +12005 => array(DEFAULT_ERROR_MESSAGE.'12005',0), +12006 => array(DEFAULT_ERROR_MESSAGE.'12006',0), +12007 => array(DEFAULT_ERROR_MESSAGE.'12007',0), +12008 => array(DEFAULT_ERROR_MESSAGE.'12008',0), +12009 => array(DEFAULT_ERROR_MESSAGE.'12009',0), +12010 => array(DEFAULT_ERROR_MESSAGE.'12010',0), +12011 => array(DEFAULT_ERROR_MESSAGE.'12011',0), +12012 => array(DEFAULT_ERROR_MESSAGE.'12012',0), +14001 => array(DEFAULT_ERROR_MESSAGE.'14001',0), +14002 => array(DEFAULT_ERROR_MESSAGE.'14002',0), +14003 => array(DEFAULT_ERROR_MESSAGE.'14003',0), +14004 => array(DEFAULT_ERROR_MESSAGE.'14004',0), +14005 => array(DEFAULT_ERROR_MESSAGE.'14005',0), +14006 => array(DEFAULT_ERROR_MESSAGE.'14006',0), +14007 => array(DEFAULT_ERROR_MESSAGE.'14007',0), +15001 => array(DEFAULT_ERROR_MESSAGE.'15001',0), +15002 => array(DEFAULT_ERROR_MESSAGE.'15002',0), +15003 => array(DEFAULT_ERROR_MESSAGE.'15003',0), +15004 => array(DEFAULT_ERROR_MESSAGE.'15004',0), +15005 => array(DEFAULT_ERROR_MESSAGE.'15005',0), +15006 => array(DEFAULT_ERROR_MESSAGE.'15006',0), +15007 => array(DEFAULT_ERROR_MESSAGE.'15007',0), +15008 => array(DEFAULT_ERROR_MESSAGE.'15008',0), +15009 => array(DEFAULT_ERROR_MESSAGE.'15009',0), +15010 => array(DEFAULT_ERROR_MESSAGE.'15010',0), +15011 => array(DEFAULT_ERROR_MESSAGE.'15011',0), +16001 => array(DEFAULT_ERROR_MESSAGE.'16001',0), +16002 => array(DEFAULT_ERROR_MESSAGE.'16002',0), +16003 => array(DEFAULT_ERROR_MESSAGE.'16003',0), +16004 => array(DEFAULT_ERROR_MESSAGE.'16004',0), +17001 => array(DEFAULT_ERROR_MESSAGE.'17001',0), +17002 => array(DEFAULT_ERROR_MESSAGE.'17002',0), +17004 => array(DEFAULT_ERROR_MESSAGE.'17004',0), +18001 => array(DEFAULT_ERROR_MESSAGE.'18001',0), +18002 => array(DEFAULT_ERROR_MESSAGE.'18002',0), +18003 => array(DEFAULT_ERROR_MESSAGE.'18003',0), +18004 => array(DEFAULT_ERROR_MESSAGE.'18004',0), +18005 => array(DEFAULT_ERROR_MESSAGE.'18005',0), +18006 => array(DEFAULT_ERROR_MESSAGE.'18006',0), +18007 => array(DEFAULT_ERROR_MESSAGE.'18007',0), +18008 => array(DEFAULT_ERROR_MESSAGE.'18008',0), +19001 => array(DEFAULT_ERROR_MESSAGE.'19001',0), +19002 => array(DEFAULT_ERROR_MESSAGE.'19002',0), +19003 => array(DEFAULT_ERROR_MESSAGE.'19003',0), +20001 => array(DEFAULT_ERROR_MESSAGE.'20001',0), +20002 => array(DEFAULT_ERROR_MESSAGE.'20002',0), +20003 => array(DEFAULT_ERROR_MESSAGE.'20003',0), +21001 => array(DEFAULT_ERROR_MESSAGE.'21001',0), +23001 => array(DEFAULT_ERROR_MESSAGE.'23001',0), +23002 => array(DEFAULT_ERROR_MESSAGE.'23002',0), +23003 => array(DEFAULT_ERROR_MESSAGE.'23003',0), +24001 => array(DEFAULT_ERROR_MESSAGE.'24001',0), +24002 => array(DEFAULT_ERROR_MESSAGE.'24002',0), +24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), +24004 => array(DEFAULT_ERROR_MESSAGE.'24004',0), +25001 => array(DEFAULT_ERROR_MESSAGE.'25001',0), +25002 => array(DEFAULT_ERROR_MESSAGE.'25002',0), +25003 => array(DEFAULT_ERROR_MESSAGE.'25003',0), +25004 => array(DEFAULT_ERROR_MESSAGE.'25004',0), +25005 => array(DEFAULT_ERROR_MESSAGE.'25005',0), +25006 => array(DEFAULT_ERROR_MESSAGE.'25006',0), +25007 => array(DEFAULT_ERROR_MESSAGE.'25007',0), +25008 => array(DEFAULT_ERROR_MESSAGE.'25008',0), +25009 => array(DEFAULT_ERROR_MESSAGE.'25009',0), +25010 => array(DEFAULT_ERROR_MESSAGE.'25010',0), +25011 => array(DEFAULT_ERROR_MESSAGE.'25011',0), +25012 => array(DEFAULT_ERROR_MESSAGE.'25012',0), +25013 => array(DEFAULT_ERROR_MESSAGE.'25013',0), +25014 => array(DEFAULT_ERROR_MESSAGE.'25014',0), +25015 => array(DEFAULT_ERROR_MESSAGE.'25015',0), +25016 => array(DEFAULT_ERROR_MESSAGE.'25016',0), +25017 => array(DEFAULT_ERROR_MESSAGE.'25017',0), +25018 => array(DEFAULT_ERROR_MESSAGE.'25018',0), +25019 => array(DEFAULT_ERROR_MESSAGE.'25019',0), +25020 => array(DEFAULT_ERROR_MESSAGE.'25020',0), +25021 => array(DEFAULT_ERROR_MESSAGE.'25021',0), +25022 => array(DEFAULT_ERROR_MESSAGE.'25022',0), +25023 => array(DEFAULT_ERROR_MESSAGE.'25023',0), +25024 => array(DEFAULT_ERROR_MESSAGE.'25024',0), +25025 => array(DEFAULT_ERROR_MESSAGE.'25025',0), +25026 => array(DEFAULT_ERROR_MESSAGE.'25026',0), +25027 => array(DEFAULT_ERROR_MESSAGE.'25027',0), +25028 => array(DEFAULT_ERROR_MESSAGE.'25028',0), +25029 => array(DEFAULT_ERROR_MESSAGE.'25029',0), +25030 => array(DEFAULT_ERROR_MESSAGE.'25030',0), +25031 => array(DEFAULT_ERROR_MESSAGE.'25031',0), +25032 => array(DEFAULT_ERROR_MESSAGE.'25032',0), +25033 => array(DEFAULT_ERROR_MESSAGE.'25033',0), +25034 => array(DEFAULT_ERROR_MESSAGE.'25034',0), +25035 => array(DEFAULT_ERROR_MESSAGE.'25035',0), +25036 => array(DEFAULT_ERROR_MESSAGE.'25036',0), +25037 => array(DEFAULT_ERROR_MESSAGE.'25037',0), +25038 => array(DEFAULT_ERROR_MESSAGE.'25038',0), +25039 => array(DEFAULT_ERROR_MESSAGE.'25039',0), +25040 => array(DEFAULT_ERROR_MESSAGE.'25040',0), +25041 => array(DEFAULT_ERROR_MESSAGE.'25041',0), +25042 => array(DEFAULT_ERROR_MESSAGE.'25042',0), +25043 => array(DEFAULT_ERROR_MESSAGE.'25043',0), +25044 => array(DEFAULT_ERROR_MESSAGE.'25044',0), +25045 => array(DEFAULT_ERROR_MESSAGE.'25045',0), +25046 => array(DEFAULT_ERROR_MESSAGE.'25046',0), +25047 => array(DEFAULT_ERROR_MESSAGE.'25047',0), +25048 => array(DEFAULT_ERROR_MESSAGE.'25048',0), +25049 => array(DEFAULT_ERROR_MESSAGE.'25049',0), +25050 => array(DEFAULT_ERROR_MESSAGE.'25050',0), +25051 => array(DEFAULT_ERROR_MESSAGE.'25051',0), +25052 => array(DEFAULT_ERROR_MESSAGE.'25052',0), +25053 => array(DEFAULT_ERROR_MESSAGE.'25053',0), +25054 => array(DEFAULT_ERROR_MESSAGE.'25054',0), +25055 => array(DEFAULT_ERROR_MESSAGE.'25055',0), +25056 => array(DEFAULT_ERROR_MESSAGE.'25056',0), +25057 => array(DEFAULT_ERROR_MESSAGE.'25057',0), +25058 => array(DEFAULT_ERROR_MESSAGE.'25058',0), +25059 => array(DEFAULT_ERROR_MESSAGE.'25059',0), +25060 => array(DEFAULT_ERROR_MESSAGE.'25060',0), +25061 => array(DEFAULT_ERROR_MESSAGE.'25061',0), +25062 => array(DEFAULT_ERROR_MESSAGE.'25062',0), +25063 => array(DEFAULT_ERROR_MESSAGE.'25063',0), +25064 => array(DEFAULT_ERROR_MESSAGE.'25064',0), +25065 => array(DEFAULT_ERROR_MESSAGE.'25065',0), +25066 => array(DEFAULT_ERROR_MESSAGE.'25066',0), +25067 => array(DEFAULT_ERROR_MESSAGE.'25067',0), +25068 => array(DEFAULT_ERROR_MESSAGE.'25068',0), +25069 => array(DEFAULT_ERROR_MESSAGE.'25069',0), +25070 => array(DEFAULT_ERROR_MESSAGE.'25070',0), +25071 => array(DEFAULT_ERROR_MESSAGE.'25071',0), +25072 => array(DEFAULT_ERROR_MESSAGE.'25072',0), +25073 => array(DEFAULT_ERROR_MESSAGE.'25073',0), +25074 => array(DEFAULT_ERROR_MESSAGE.'25074',0), +25075 => array(DEFAULT_ERROR_MESSAGE.'25075',0), +25077 => array(DEFAULT_ERROR_MESSAGE.'25077',0), +25078 => array(DEFAULT_ERROR_MESSAGE.'25078',0), +25079 => array(DEFAULT_ERROR_MESSAGE.'25079',0), +25080 => array(DEFAULT_ERROR_MESSAGE.'25080',0), +25081 => array(DEFAULT_ERROR_MESSAGE.'25081',0), +25082 => array(DEFAULT_ERROR_MESSAGE.'25082',0), +25083 => array(DEFAULT_ERROR_MESSAGE.'25083',0), +25084 => array(DEFAULT_ERROR_MESSAGE.'25084',0), +25085 => array(DEFAULT_ERROR_MESSAGE.'25085',0), +25086 => array(DEFAULT_ERROR_MESSAGE.'25086',0), +25087 => array(DEFAULT_ERROR_MESSAGE.'25087',0), +25088 => array(DEFAULT_ERROR_MESSAGE.'25088',0), +25089 => array(DEFAULT_ERROR_MESSAGE.'25089',0), +25090 => array(DEFAULT_ERROR_MESSAGE.'25090',0), +25091 => array(DEFAULT_ERROR_MESSAGE.'25091',0), +25092 => array(DEFAULT_ERROR_MESSAGE.'25092',0), +25093 => array(DEFAULT_ERROR_MESSAGE.'25093',0), +25094 => array(DEFAULT_ERROR_MESSAGE.'25094',0), +25095 => array(DEFAULT_ERROR_MESSAGE.'25095',0), +25096 => array(DEFAULT_ERROR_MESSAGE.'25096',0), +25097 => array(DEFAULT_ERROR_MESSAGE.'25097',0), +25098 => array(DEFAULT_ERROR_MESSAGE.'25098',0), +25099 => array(DEFAULT_ERROR_MESSAGE.'25099',0), +25100 => array(DEFAULT_ERROR_MESSAGE.'25100',0), +25101 => array(DEFAULT_ERROR_MESSAGE.'25101',0), +25102 => array(DEFAULT_ERROR_MESSAGE.'25102',0), +25103 => array(DEFAULT_ERROR_MESSAGE.'25103',0), +25104 => array(DEFAULT_ERROR_MESSAGE.'25104',0), +25105 => array(DEFAULT_ERROR_MESSAGE.'25105',0), +25106 => array(DEFAULT_ERROR_MESSAGE.'25106',0), +25107 => array(DEFAULT_ERROR_MESSAGE.'25107',0), +25108 => array(DEFAULT_ERROR_MESSAGE.'25108',0), +25109 => array(DEFAULT_ERROR_MESSAGE.'25109',0), +25110 => array(DEFAULT_ERROR_MESSAGE.'25110',0), +25111 => array(DEFAULT_ERROR_MESSAGE.'25111',0), +25112 => array(DEFAULT_ERROR_MESSAGE.'25112',0), +25113 => array(DEFAULT_ERROR_MESSAGE.'25113',0), +25114 => array(DEFAULT_ERROR_MESSAGE.'25114',0), +25115 => array(DEFAULT_ERROR_MESSAGE.'25115',0), +25116 => array(DEFAULT_ERROR_MESSAGE.'25116',0), +25117 => array(DEFAULT_ERROR_MESSAGE.'25117',0), +25118 => array(DEFAULT_ERROR_MESSAGE.'25118',0), +25119 => array(DEFAULT_ERROR_MESSAGE.'25119',0), +25120 => array(DEFAULT_ERROR_MESSAGE.'25120',0), +25121 => array(DEFAULT_ERROR_MESSAGE.'25121',0), +25122 => array(DEFAULT_ERROR_MESSAGE.'25122',0), +25123 => array(DEFAULT_ERROR_MESSAGE.'25123',0), +25124 => array(DEFAULT_ERROR_MESSAGE.'25124',0), +25125 => array(DEFAULT_ERROR_MESSAGE.'25125',0), +25126 => array(DEFAULT_ERROR_MESSAGE.'25126',0), +25127 => array(DEFAULT_ERROR_MESSAGE.'25127',0), +25128 => array(DEFAULT_ERROR_MESSAGE.'25128',0), +25129 => array(DEFAULT_ERROR_MESSAGE.'25129',0), +25130 => array(DEFAULT_ERROR_MESSAGE.'25130',0), +25131 => array(DEFAULT_ERROR_MESSAGE.'25131',0), +25500 => array(DEFAULT_ERROR_MESSAGE.'25500',0), +24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), +24004 => array(DEFAULT_ERROR_MESSAGE.'24004',0), +24005 => array(DEFAULT_ERROR_MESSAGE.'24005',0), +24006 => array(DEFAULT_ERROR_MESSAGE.'24006',0), +24007 => array(DEFAULT_ERROR_MESSAGE.'24007',0), +24008 => array(DEFAULT_ERROR_MESSAGE.'24008',0), +24009 => array(DEFAULT_ERROR_MESSAGE.'24009',0), +24010 => array(DEFAULT_ERROR_MESSAGE.'24010',0), +24011 => array(DEFAULT_ERROR_MESSAGE.'24011',0), +24012 => array(DEFAULT_ERROR_MESSAGE.'24012',0), +24013 => array(DEFAULT_ERROR_MESSAGE.'24013',0), +24014 => array(DEFAULT_ERROR_MESSAGE.'24014',0), +24015 => array(DEFAULT_ERROR_MESSAGE.'24015',0), +22001 => array(DEFAULT_ERROR_MESSAGE.'22001',0), +22002 => array(DEFAULT_ERROR_MESSAGE.'22002',0), +22004 => array(DEFAULT_ERROR_MESSAGE.'22004',0), +22005 => array(DEFAULT_ERROR_MESSAGE.'22005',0), +22006 => array(DEFAULT_ERROR_MESSAGE.'22006',0), +22007 => array(DEFAULT_ERROR_MESSAGE.'22007',0), +22008 => array(DEFAULT_ERROR_MESSAGE.'22008',0), +22009 => array(DEFAULT_ERROR_MESSAGE.'22009',0), +22010 => array(DEFAULT_ERROR_MESSAGE.'22010',0), +22011 => array(DEFAULT_ERROR_MESSAGE.'22011',0), +22012 => array(DEFAULT_ERROR_MESSAGE.'22012',0), +22013 => array(DEFAULT_ERROR_MESSAGE.'22013',0), +22014 => array(DEFAULT_ERROR_MESSAGE.'22014',0), +22015 => array(DEFAULT_ERROR_MESSAGE.'22015',0), +22016 => array(DEFAULT_ERROR_MESSAGE.'22016',0), +22017 => array(DEFAULT_ERROR_MESSAGE.'22017',0), +22018 => array(DEFAULT_ERROR_MESSAGE.'22018',0), +22019 => array(DEFAULT_ERROR_MESSAGE.'22019',0), +22020 => array(DEFAULT_ERROR_MESSAGE.'22020',0), +13001 => array(DEFAULT_ERROR_MESSAGE.'13001',0), +13002 => array(DEFAULT_ERROR_MESSAGE.'13002',0), +1001 => array(DEFAULT_ERROR_MESSAGE.'1001',0), +1002 => array(DEFAULT_ERROR_MESSAGE.'1002',0), +1003 => array(DEFAULT_ERROR_MESSAGE.'1003',0), +1004 => array(DEFAULT_ERROR_MESSAGE.'1004',0), +1005 => array(DEFAULT_ERROR_MESSAGE.'1005',0), +1006 => array(DEFAULT_ERROR_MESSAGE.'1006',0), +1007 => array(DEFAULT_ERROR_MESSAGE.'1007',0), +1008 => array(DEFAULT_ERROR_MESSAGE.'1008',0), +1009 => array(DEFAULT_ERROR_MESSAGE.'1009',0), +1010 => array(DEFAULT_ERROR_MESSAGE.'1010',0), +1011 => array(DEFAULT_ERROR_MESSAGE.'1011',0), +26000 => array(DEFAULT_ERROR_MESSAGE.'26000',0), +26001 => array(DEFAULT_ERROR_MESSAGE.'26001',0), +26002 => array(DEFAULT_ERROR_MESSAGE.'26002',0), +26003 => array(DEFAULT_ERROR_MESSAGE.'26003',0), +26004 => array(DEFAULT_ERROR_MESSAGE.'26004',0), +26005 => array(DEFAULT_ERROR_MESSAGE.'26005',0), +26006 => array(DEFAULT_ERROR_MESSAGE.'26006',0), +26007 => array(DEFAULT_ERROR_MESSAGE.'26007',0), +26008 => array(DEFAULT_ERROR_MESSAGE.'26008',0), +26009 => array(DEFAULT_ERROR_MESSAGE.'26009',0), +26010 => array(DEFAULT_ERROR_MESSAGE.'26010',0), +26011 => array(DEFAULT_ERROR_MESSAGE.'26011',0), +26012 => array(DEFAULT_ERROR_MESSAGE.'26012',0), +26013 => array(DEFAULT_ERROR_MESSAGE.'26013',0), +26014 => array(DEFAULT_ERROR_MESSAGE.'26014',0), +26015 => array(DEFAULT_ERROR_MESSAGE.'26015',0), +26016 => array(DEFAULT_ERROR_MESSAGE.'26016',0), + +27001 => array(DEFAULT_ERROR_MESSAGE.'27001',0), +27002 => array(DEFAULT_ERROR_MESSAGE.'27002',0), +27003 => array(DEFAULT_ERROR_MESSAGE.'27003',0), +27004 => array(DEFAULT_ERROR_MESSAGE.'27004',0), +27005 => array(DEFAULT_ERROR_MESSAGE.'27005',0), +27006 => array(DEFAULT_ERROR_MESSAGE.'27006',0), +27007 => array(DEFAULT_ERROR_MESSAGE.'27007',0), +27008 => array(DEFAULT_ERROR_MESSAGE.'27008',0), +27009 => array(DEFAULT_ERROR_MESSAGE.'27009',0), +27010 => array(DEFAULT_ERROR_MESSAGE.'27010',0), +27011 => array(DEFAULT_ERROR_MESSAGE.'27011',0), +27012 => array(DEFAULT_ERROR_MESSAGE.'27012',0), +27013 => array(DEFAULT_ERROR_MESSAGE.'27013',0), +27014 => array(DEFAULT_ERROR_MESSAGE.'27014',0), +27015 => array(DEFAULT_ERROR_MESSAGE.'27015',0), + +28001 => array(DEFAULT_ERROR_MESSAGE.'28001',0), +28002 => array(DEFAULT_ERROR_MESSAGE.'28002',0), +28003 => array(DEFAULT_ERROR_MESSAGE.'28003',0), +28004 => array(DEFAULT_ERROR_MESSAGE.'28004',0), +28005 => array(DEFAULT_ERROR_MESSAGE.'28005',0), +28006 => array(DEFAULT_ERROR_MESSAGE.'28006',0), +28007 => array(DEFAULT_ERROR_MESSAGE.'28007',0), + +29201 => array(DEFAULT_ERROR_MESSAGE.'28001',0), +29202 => array(DEFAULT_ERROR_MESSAGE.'28002',0), +29203 => array(DEFAULT_ERROR_MESSAGE.'28003',0), +29204 => array(DEFAULT_ERROR_MESSAGE.'28004',0), +29205 => array(DEFAULT_ERROR_MESSAGE.'28005',0), +29206 => array(DEFAULT_ERROR_MESSAGE.'28006',0), +29207 => array(DEFAULT_ERROR_MESSAGE.'28007',0), +29208 => array(DEFAULT_ERROR_MESSAGE.'28008',0), +29209 => array(DEFAULT_ERROR_MESSAGE.'28009',0), +29210 => array(DEFAULT_ERROR_MESSAGE.'28010',0), + +); + +?> diff --git a/ext/php-gettext/AUTHORS b/ext/php-gettext/AUTHORS new file mode 100644 index 0000000..d94a8f1 --- /dev/null +++ b/ext/php-gettext/AUTHORS @@ -0,0 +1,3 @@ +Danilo Segan +Nico Kaiser (contributed most changes between 1.0.2 and 1.0.3, bugfix for 1.0.5) +Steven Armstrong (gettext.inc, leading to 1.0.6) diff --git a/ext/php-gettext/COPYING b/ext/php-gettext/COPYING new file mode 100644 index 0000000..45645b4 --- /dev/null +++ b/ext/php-gettext/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ext/php-gettext/Makefile b/ext/php-gettext/Makefile new file mode 100644 index 0000000..42cbed0 --- /dev/null +++ b/ext/php-gettext/Makefile @@ -0,0 +1,38 @@ +PACKAGE = php-gettext-$(VERSION) +VERSION = 1.0.11 + +DIST_FILES = \ + gettext.php \ + gettext.inc \ + streams.php \ + AUTHORS \ + README \ + COPYING \ + Makefile \ + examples/index.php \ + examples/pigs_dropin.php \ + examples/pigs_fallback.php \ + examples/locale/sr_CS/LC_MESSAGES/messages.po \ + examples/locale/sr_CS/LC_MESSAGES/messages.mo \ + examples/locale/de_CH/LC_MESSAGES/messages.po \ + examples/locale/de_CH/LC_MESSAGES/messages.mo \ + examples/update \ + tests/LocalesTest.php \ + tests/ParsingTest.php + +check: + phpunit --verbose tests + +dist: check + if [ -d $(PACKAGE) ]; then \ + rm -rf $(PACKAGE); \ + fi; \ + mkdir $(PACKAGE); \ + if [ -d $(PACKAGE) ]; then \ + cp -rp --parents $(DIST_FILES) $(PACKAGE); \ + tar cvzf $(PACKAGE).tar.gz $(PACKAGE); \ + rm -rf $(PACKAGE); \ + fi; + +clean: + rm -f $(PACKAGE).tar.gz diff --git a/ext/php-gettext/README b/ext/php-gettext/README new file mode 100644 index 0000000..f5a5f06 --- /dev/null +++ b/ext/php-gettext/README @@ -0,0 +1,161 @@ +PHP-gettext 1.0 (https://launchpad.net/php-gettext) + +Copyright 2003, 2006, 2009 -- Danilo "angry with PHP[1]" Segan +Licensed under GPLv2 (or any later version, see COPYING) + +[1] PHP is actually cyrillic, and translates roughly to + "works-doesn't-work" (UTF-8: РаЎО-Не-РаЎО) + + +Introduction + + How many times did you look for a good translation tool, and + found out that gettext is best for the job? Many times. + + How many times did you try to use gettext in PHP, but failed + miserably, because either your hosting provider didn't support + it, or the server didn't have adequate locale? Many times. + + Well, this is a solution to your needs. It allows using gettext + tools for managing translations, yet it doesn't require gettext + library at all. It parses generated MO files directly, and thus + might be a bit slower than the (maybe provided) gettext library. + + PHP-gettext is a simple reader for GNU gettext MO files. Those + are binary containers for translations, produced by GNU msgfmt. + +Why? + + I got used to having gettext work even without gettext + library. It's there in my favourite language Python, so I was + surprised that I couldn't find it in PHP. I even Googled for it, + but to no avail. + + So, I said, what the heck, I'm going to write it for this + disguisting language of PHP, because I'm often constrained to it. + +Features + + o Support for simple translations + Just define a simple alias for translate() function (suggested + use of _() or gettext(); see provided example). + + o Support for ngettext calls (plural forms, see a note under bugs) + You may also use plural forms. Translations in MO files need to + provide this, and they must also provide "plural-forms" header. + Please see 'info gettext' for more details. + + o Support for reading straight files, or strings (!!!) + Since I can imagine many different backends for reading in the MO + file data, I used imaginary abstract class StreamReader to do all + the input (check streams.php). For your convenience, I've already + provided two classes for reading files: FileReader and + StringReader (CachedFileReader is a combination of the two: it + loads entire file contents into a string, and then works on that). + See example below for usage. You can for instance use StringReader + when you read in data from a database, or you can create your own + derivative of StreamReader for anything you like. + + +Bugs + + Report them on https://bugs.launchpad.net/php-gettext + +Usage + + Put files streams.php and gettext.php somewhere you can load them + from, and require 'em in where you want to use them. + + Then, create one 'stream reader' (a class that provides functions + like read(), seekto(), currentpos() and length()) which will + provide data for the 'gettext_reader', with eg. + $streamer = new FileStream('data.mo'); + + Then, use that as a parameter to gettext_reader constructor: + $wohoo = new gettext_reader($streamer); + + If you want to disable pre-loading of entire message catalog in + memory (if, for example, you have a multi-thousand message catalog + which you'll use only occasionally), use "false" for second + parameter to gettext_reader constructor: + $wohoo = new gettext_reader($streamer, false); + + From now on, you have all the benefits of gettext data at your + disposal, so may run: + print $wohoo->translate("This is a test"); + print $wohoo->ngettext("%d bird", "%d birds", $birds); + + You might need to pass parameter "-k" to xgettext to make it + extract all the strings. In above example, try with + xgettext -ktranslate -kngettext:1,2 file.php + what should create messages.po which contains two messages for + translation. + + I suggest creating simple aliases for these functions (see + example/pigs.php for how do I do it, which means it's probably a + bad way). + + +Usage with gettext.inc (standard gettext interfaces emulation) + + Check example in examples/pig_dropin.php, basically you include + gettext.inc and use all the standard gettext interfaces as + documented on: + + http://www.php.net/gettext + + The only catch is that you can check return value of setlocale() + to see if your locale is system supported or not. + + +Example + + See in examples/ subdirectory. There are a couple of files. + pigs.php is an example, serbian.po is a translation to Serbian + language, and serbian.mo is generated with + msgfmt -o serbian.mo serbian.po + There is also simple "update" script that can be used to generate + POT file and to update the translation using msgmerge. + +TODO: + + o Improve speed to be even more comparable to the native gettext + implementation. + + o Try to use hash tables in MO files: with pre-loading, would it + be useful at all? + +Never-asked-questions: + + o Why did you mark this as version 1.0 when this is the first code + release? + + Well, it's quite simple. I consider that the first released thing + should be labeled "version 1" (first, right?). Zero is there to + indicate that there's zero improvement and/or change compared to + "version 1". + + I plan to use version numbers 1.0.* for small bugfixes, and to + release 1.1 as "first stable release of version 1". + + This may trick someone that this is actually useful software, but + as with any other free software, I take NO RESPONSIBILITY for + creating such a masterpiece that will smoke crack, trash your + hard disk, and make lasers in your CD device dance to the tune of + Mozart's 40th Symphony (there is one like that, right?). + + o Can I...? + + Yes, you can. This is free software (as in freedom, free speech), + and you might do whatever you wish with it, provided you do not + limit freedom of others (GPL). + + I'm considering licensing this under LGPL, but I *do* want + *every* PHP-gettext user to contribute and respect ideas of free + software, so don't count on it happening anytime soon. + + I'm sorry that I'm taking away your freedom of taking others' + freedom away, but I believe that's neglible as compared to what + freedoms you could take away. ;-) + + Uhm, whatever. diff --git a/ext/php-gettext/gettext.inc b/ext/php-gettext/gettext.inc new file mode 100644 index 0000000..686b99c --- /dev/null +++ b/ext/php-gettext/gettext.inc @@ -0,0 +1,536 @@ + + Copyright (c) 2009 Danilo Segan + + Drop in replacement for native gettext. + + This file is part of PHP-gettext. + + PHP-gettext is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext 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. + + You should have received a copy of the GNU General Public License + along with PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* +LC_CTYPE 0 +LC_NUMERIC 1 +LC_TIME 2 +LC_COLLATE 3 +LC_MONETARY 4 +LC_MESSAGES 5 +LC_ALL 6 +*/ + +// LC_MESSAGES is not available if php-gettext is not loaded +// while the other constants are already available from session extension. +if (!defined('LC_MESSAGES')) { + define('LC_MESSAGES', 5); +} + +require('streams.php'); +require('gettext.php'); + + +// Variables + +global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE; +$text_domains = array(); +$default_domain = 'messages'; +$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL'); +$EMULATEGETTEXT = 0; +$CURRENTLOCALE = ''; + +/* Class to hold a single domain included in $text_domains. */ +class domain { + var $l10n; + var $path; + var $codeset; +} + +// Utility functions + +/** + * Return a list of locales to try for any POSIX-style locale specification. + */ +function get_list_of_locales($locale) { + /* Figure out all possible locale names and start with the most + * specific ones. I.e. for sr_CS.UTF-8@latin, look through all of + * sr_CS.UTF-8@latin, sr_CS@latin, sr@latin, sr_CS.UTF-8, sr_CS, sr. + */ + $locale_names = array(); + $lang = NULL; + $country = NULL; + $charset = NULL; + $modifier = NULL; + if ($locale) { + if (preg_match("/^(?P[a-z]{2,3})" // language code + ."(?:_(?P[A-Z]{2}))?" // country code + ."(?:\.(?P[-A-Za-z0-9_]+))?" // charset + ."(?:@(?P[-A-Za-z0-9_]+))?$/", // @ modifier + $locale, $matches)) { + + if (isset($matches["lang"])) $lang = $matches["lang"]; + if (isset($matches["country"])) $country = $matches["country"]; + if (isset($matches["charset"])) $charset = $matches["charset"]; + if (isset($matches["modifier"])) $modifier = $matches["modifier"]; + + if ($modifier) { + if ($country) { + if ($charset) + array_push($locale_names, "${lang}_$country.$charset@$modifier"); + array_push($locale_names, "${lang}_$country@$modifier"); + } elseif ($charset) + array_push($locale_names, "${lang}.$charset@$modifier"); + array_push($locale_names, "$lang@$modifier"); + } + if ($country) { + if ($charset) + array_push($locale_names, "${lang}_$country.$charset"); + array_push($locale_names, "${lang}_$country"); + } elseif ($charset) + array_push($locale_names, "${lang}.$charset"); + array_push($locale_names, $lang); + } + + // If the locale name doesn't match POSIX style, just include it as-is. + if (!in_array($locale, $locale_names)) + array_push($locale_names, $locale); + } + return $locale_names; +} + +/** + * Utility function to get a StreamReader for the given text domain. + */ +function _get_reader($domain=null, $category=5, $enable_cache=true) { + global $text_domains, $default_domain, $LC_CATEGORIES; + if (!isset($domain)) $domain = $default_domain; + if (!isset($text_domains[$domain]->l10n)) { + // get the current locale + $locale = _setlocale(LC_MESSAGES, 0); + $bound_path = isset($text_domains[$domain]->path) ? + $text_domains[$domain]->path : './'; + $subpath = $LC_CATEGORIES[$category] ."/$domain.mo"; + + $locale_names = get_list_of_locales($locale); + $input = null; + foreach ($locale_names as $locale) { + $full_path = $bound_path . $locale . "/" . $subpath; + if (file_exists($full_path)) { + $input = new FileReader($full_path); + break; + } + } + + if (!array_key_exists($domain, $text_domains)) { + // Initialize an empty domain object. + $text_domains[$domain] = new domain(); + } + $text_domains[$domain]->l10n = new gettext_reader($input, + $enable_cache); + } + return $text_domains[$domain]->l10n; +} + +/** + * Returns whether we are using our emulated gettext API or PHP built-in one. + */ +function locale_emulation() { + global $EMULATEGETTEXT; + return $EMULATEGETTEXT; +} + +/** + * Checks if the current locale is supported on this system. + */ +function _check_locale_and_function($function=false) { + global $EMULATEGETTEXT; + if ($function and !function_exists($function)) + return false; + return !$EMULATEGETTEXT; +} + +/** + * Get the codeset for the given domain. + */ +function _get_codeset($domain=null) { + global $text_domains, $default_domain, $LC_CATEGORIES; + if (!isset($domain)) $domain = $default_domain; + return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding'); +} + +/** + * Convert the given string to the encoding set by bind_textdomain_codeset. + */ +function _encode($text) { + $source_encoding = mb_detect_encoding($text); + $target_encoding = _get_codeset(); + if ($source_encoding != $target_encoding) { + return mb_convert_encoding($text, $target_encoding, $source_encoding); + } + else { + return $text; + } +} + + +// Custom implementation of the standard gettext related functions + +/** + * Returns passed in $locale, or environment variable $LANG if $locale == ''. + */ +function _get_default_locale($locale) { + if ($locale == '') // emulate variable support + return getenv('LANG'); + else + return $locale; +} + +/** + * Sets a requested locale, if needed emulates it. + */ +function _setlocale($category, $locale) { + global $CURRENTLOCALE, $EMULATEGETTEXT; + if ($locale === 0) { // use === to differentiate between string "0" + if ($CURRENTLOCALE != '') + return $CURRENTLOCALE; + else + // obey LANG variable, maybe extend to support all of LC_* vars + // even if we tried to read locale without setting it first + return _setlocale($category, $CURRENTLOCALE); + } else { + if (function_exists('setlocale')) { + $ret = setlocale($category, $locale); + if (($locale == '' and !$ret) or // failed setting it by env + ($locale != '' and $ret != $locale)) { // failed setting it + // Failed setting it according to environment. + $CURRENTLOCALE = _get_default_locale($locale); + $EMULATEGETTEXT = 1; + } else { + $CURRENTLOCALE = $ret; + $EMULATEGETTEXT = 0; + } + } else { + // No function setlocale(), emulate it all. + $CURRENTLOCALE = _get_default_locale($locale); + $EMULATEGETTEXT = 1; + } + // Allow locale to be changed on the go for one translation domain. + global $text_domains, $default_domain; + if (array_key_exists($default_domain, $text_domains)) { + unset($text_domains[$default_domain]->l10n); + } + return $CURRENTLOCALE; + } +} + +/** + * Sets the path for a domain. + */ +function _bindtextdomain($domain, $path) { + global $text_domains; + // ensure $path ends with a slash ('/' should work for both, but lets still play nice) + if (substr(php_uname(), 0, 7) == "Windows") { + if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/') + $path .= '\\'; + } else { + if ($path[strlen($path)-1] != '/') + $path .= '/'; + } + if (!array_key_exists($domain, $text_domains)) { + // Initialize an empty domain object. + $text_domains[$domain] = new domain(); + } + $text_domains[$domain]->path = $path; +} + +/** + * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned. + */ +function _bind_textdomain_codeset($domain, $codeset) { + global $text_domains; + $text_domains[$domain]->codeset = $codeset; +} + +/** + * Sets the default domain. + */ +function _textdomain($domain) { + global $default_domain; + $default_domain = $domain; +} + +/** + * Lookup a message in the current domain. + */ +function _gettext($msgid) { + $l10n = _get_reader(); + return _encode($l10n->translate($msgid)); +} + +/** + * Alias for gettext. + */ +function __($msgid) { + return _gettext($msgid); +} + +/** + * Plural version of gettext. + */ +function _ngettext($singular, $plural, $number) { + $l10n = _get_reader(); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Override the current domain. + */ +function _dgettext($domain, $msgid) { + $l10n = _get_reader($domain); + return _encode($l10n->translate($msgid)); +} + +/** + * Plural version of dgettext. + */ +function _dngettext($domain, $singular, $plural, $number) { + $l10n = _get_reader($domain); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Overrides the domain and category for a single lookup. + */ +function _dcgettext($domain, $msgid, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->translate($msgid)); +} +/** + * Plural version of dcgettext. + */ +function _dcngettext($domain, $singular, $plural, $number, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->ngettext($singular, $plural, $number)); +} + +/** + * Context version of gettext. + */ +function _pgettext($context, $msgid) { + $l10n = _get_reader(); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Override the current domain in a context gettext call. + */ +function _dpgettext($domain, $context, $msgid) { + $l10n = _get_reader($domain); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Overrides the domain and category for a single context-based lookup. + */ +function _dcpgettext($domain, $context, $msgid, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->pgettext($context, $msgid)); +} + +/** + * Context version of ngettext. + */ +function _npgettext($context, $singular, $plural) { + $l10n = _get_reader(); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + +/** + * Override the current domain in a context ngettext call. + */ +function _dnpgettext($domain, $context, $singular, $plural) { + $l10n = _get_reader($domain); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + +/** + * Overrides the domain and category for a plural context-based lookup. + */ +function _dcnpgettext($domain, $context, $singular, $plural, $category) { + $l10n = _get_reader($domain, $category); + return _encode($l10n->npgettext($context, $singular, $plural)); +} + + + +// Wrappers to use if the standard gettext functions are available, +// but the current locale is not supported by the system. +// Use the standard impl if the current locale is supported, use the +// custom impl otherwise. + +function T_setlocale($category, $locale) { + return _setlocale($category, $locale); +} + +function T_bindtextdomain($domain, $path) { + if (_check_locale_and_function()) return bindtextdomain($domain, $path); + else return _bindtextdomain($domain, $path); +} +function T_bind_textdomain_codeset($domain, $codeset) { + // bind_textdomain_codeset is available only in PHP 4.2.0+ + if (_check_locale_and_function('bind_textdomain_codeset')) + return bind_textdomain_codeset($domain, $codeset); + else return _bind_textdomain_codeset($domain, $codeset); +} +function T_textdomain($domain) { + if (_check_locale_and_function()) return textdomain($domain); + else return _textdomain($domain); +} +function T_gettext($msgid) { + if (_check_locale_and_function()) return gettext($msgid); + else return _gettext($msgid); +} +function T_($msgid) { + if (_check_locale_and_function()) return _($msgid); + return __($msgid); +} +function T_ngettext($singular, $plural, $number) { + if (_check_locale_and_function()) + return ngettext($singular, $plural, $number); + else return _ngettext($singular, $plural, $number); +} +function T_dgettext($domain, $msgid) { + if (_check_locale_and_function()) return dgettext($domain, $msgid); + else return _dgettext($domain, $msgid); +} +function T_dngettext($domain, $singular, $plural, $number) { + if (_check_locale_and_function()) + return dngettext($domain, $singular, $plural, $number); + else return _dngettext($domain, $singular, $plural, $number); +} +function T_dcgettext($domain, $msgid, $category) { + if (_check_locale_and_function()) + return dcgettext($domain, $msgid, $category); + else return _dcgettext($domain, $msgid, $category); +} +function T_dcngettext($domain, $singular, $plural, $number, $category) { + if (_check_locale_and_function()) + return dcngettext($domain, $singular, $plural, $number, $category); + else return _dcngettext($domain, $singular, $plural, $number, $category); +} + +function T_pgettext($context, $msgid) { + if (_check_locale_and_function('pgettext')) + return pgettext($context, $msgid); + else + return _pgettext($context, $msgid); +} + +function T_dpgettext($domain, $context, $msgid) { + if (_check_locale_and_function('dpgettext')) + return dpgettext($domain, $context, $msgid); + else + return _dpgettext($domain, $context, $msgid); +} + +function T_dcpgettext($domain, $context, $msgid, $category) { + if (_check_locale_and_function('dcpgettext')) + return dcpgettext($domain, $context, $msgid, $category); + else + return _dcpgettext($domain, $context, $msgid, $category); +} + +function T_npgettext($context, $singular, $plural, $number) { + if (_check_locale_and_function('npgettext')) + return npgettext($context, $singular, $plural, $number); + else + return _npgettext($context, $singular, $plural, $number); +} + +function T_dnpgettext($domain, $context, $singular, $plural, $number) { + if (_check_locale_and_function('dnpgettext')) + return dnpgettext($domain, $context, $singular, $plural, $number); + else + return _dnpgettext($domain, $context, $singular, $plural, $number); +} + +function T_dcnpgettext($domain, $context, $singular, $plural, + $number, $category) { + if (_check_locale_and_function('dcnpgettext')) + return dcnpgettext($domain, $context, $singular, + $plural, $number, $category); + else + return _dcnpgettext($domain, $context, $singular, + $plural, $number, $category); +} + + + +// Wrappers used as a drop in replacement for the standard gettext functions + +if (!function_exists('gettext')) { + function bindtextdomain($domain, $path) { + return _bindtextdomain($domain, $path); + } + function bind_textdomain_codeset($domain, $codeset) { + return _bind_textdomain_codeset($domain, $codeset); + } + function textdomain($domain) { + return _textdomain($domain); + } + function gettext($msgid) { + return _gettext($msgid); + } + function _($msgid) { + return __($msgid); + } + function ngettext($singular, $plural, $number) { + return _ngettext($singular, $plural, $number); + } + function dgettext($domain, $msgid) { + return _dgettext($domain, $msgid); + } + function dngettext($domain, $singular, $plural, $number) { + return _dngettext($domain, $singular, $plural, $number); + } + function dcgettext($domain, $msgid, $category) { + return _dcgettext($domain, $msgid, $category); + } + function dcngettext($domain, $singular, $plural, $number, $category) { + return _dcngettext($domain, $singular, $plural, $number, $category); + } + function pgettext($context, $msgid) { + return _pgettext($context, $msgid); + } + function npgettext($context, $singular, $plural, $number) { + return _npgettext($context, $singular, $plural, $number); + } + function dpgettext($domain, $context, $msgid) { + return _dpgettext($domain, $context, $msgid); + } + function dnpgettext($domain, $context, $singular, $plural, $number) { + return _dnpgettext($domain, $context, $singular, $plural, $number); + } + function dcpgettext($domain, $context, $msgid, $category) { + return _dcpgettext($domain, $context, $msgid, $category); + } + function dcnpgettext($domain, $context, $singular, $plural, + $number, $category) { + return _dcnpgettext($domain, $context, $singular, $plural, + $number, $category); + } +} + +?> diff --git a/ext/php-gettext/gettext.php b/ext/php-gettext/gettext.php new file mode 100644 index 0000000..d80b69a --- /dev/null +++ b/ext/php-gettext/gettext.php @@ -0,0 +1,432 @@ +. + Copyright (c) 2005 Nico Kaiser + + This file is part of PHP-gettext. + + PHP-gettext is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext 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. + + You should have received a copy of the GNU General Public License + along with PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/** + * Provides a simple gettext replacement that works independently from + * the system's gettext abilities. + * It can read MO files and use them for translating strings. + * The files are passed to gettext_reader as a Stream (see streams.php) + * + * This version has the ability to cache all strings and translations to + * speed up the string lookup. + * While the cache is enabled by default, it can be switched off with the + * second parameter in the constructor (e.g. whenusing very large MO files + * that you don't want to keep in memory) + */ +class gettext_reader { + //public: + var $error = 0; // public variable that holds error code (0 if no error) + + //private: + var $BYTEORDER = 0; // 0: low endian, 1: big endian + var $STREAM = NULL; + var $short_circuit = false; + var $enable_cache = false; + var $originals = NULL; // offset of original table + var $translations = NULL; // offset of translation table + var $pluralheader = NULL; // cache header field for plural forms + var $total = 0; // total string count + var $table_originals = NULL; // table for original strings (offsets) + var $table_translations = NULL; // table for translated strings (offsets) + var $cache_translations = NULL; // original -> translation mapping + + + /* Methods */ + + + /** + * Reads a 32bit Integer from the Stream + * + * @access private + * @return Integer from the Stream + */ + function readint() { + if ($this->BYTEORDER == 0) { + // low endian + $input=unpack('V', $this->STREAM->read(4)); + return array_shift($input); + } else { + // big endian + $input=unpack('N', $this->STREAM->read(4)); + return array_shift($input); + } + } + + function read($bytes) { + return $this->STREAM->read($bytes); + } + + /** + * Reads an array of Integers from the Stream + * + * @param int count How many elements should be read + * @return Array of Integers + */ + function readintarray($count) { + if ($this->BYTEORDER == 0) { + // low endian + return unpack('V'.$count, $this->STREAM->read(4 * $count)); + } else { + // big endian + return unpack('N'.$count, $this->STREAM->read(4 * $count)); + } + } + + /** + * Constructor + * + * @param object Reader the StreamReader object + * @param boolean enable_cache Enable or disable caching of strings (default on) + */ + function gettext_reader($Reader, $enable_cache = true) { + // If there isn't a StreamReader, turn on short circuit mode. + if (! $Reader || isset($Reader->error) ) { + $this->short_circuit = true; + return; + } + + // Caching can be turned off + $this->enable_cache = $enable_cache; + + $MAGIC1 = "\x95\x04\x12\xde"; + $MAGIC2 = "\xde\x12\x04\x95"; + + $this->STREAM = $Reader; + $magic = $this->read(4); + if ($magic == $MAGIC1) { + $this->BYTEORDER = 1; + } elseif ($magic == $MAGIC2) { + $this->BYTEORDER = 0; + } else { + $this->error = 1; // not MO file + return false; + } + + // FIXME: Do we care about revision? We should. + $revision = $this->readint(); + + $this->total = $this->readint(); + $this->originals = $this->readint(); + $this->translations = $this->readint(); + } + + /** + * Loads the translation tables from the MO file into the cache + * If caching is enabled, also loads all strings into a cache + * to speed up translation lookups + * + * @access private + */ + function load_tables() { + if (is_array($this->cache_translations) && + is_array($this->table_originals) && + is_array($this->table_translations)) + return; + + /* get original and translations tables */ + if (!is_array($this->table_originals)) { + $this->STREAM->seekto($this->originals); + $this->table_originals = $this->readintarray($this->total * 2); + } + if (!is_array($this->table_translations)) { + $this->STREAM->seekto($this->translations); + $this->table_translations = $this->readintarray($this->total * 2); + } + + if ($this->enable_cache) { + $this->cache_translations = array (); + /* read all strings in the cache */ + for ($i = 0; $i < $this->total; $i++) { + $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); + $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); + $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); + $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); + $this->cache_translations[$original] = $translation; + } + } + } + + /** + * Returns a string from the "originals" table + * + * @access private + * @param int num Offset number of original string + * @return string Requested string if found, otherwise '' + */ + function get_original_string($num) { + $length = $this->table_originals[$num * 2 + 1]; + $offset = $this->table_originals[$num * 2 + 2]; + if (! $length) + return ''; + $this->STREAM->seekto($offset); + $data = $this->STREAM->read($length); + return (string)$data; + } + + /** + * Returns a string from the "translations" table + * + * @access private + * @param int num Offset number of original string + * @return string Requested string if found, otherwise '' + */ + function get_translation_string($num) { + $length = $this->table_translations[$num * 2 + 1]; + $offset = $this->table_translations[$num * 2 + 2]; + if (! $length) + return ''; + $this->STREAM->seekto($offset); + $data = $this->STREAM->read($length); + return (string)$data; + } + + /** + * Binary search for string + * + * @access private + * @param string string + * @param int start (internally used in recursive function) + * @param int end (internally used in recursive function) + * @return int string number (offset in originals table) + */ + function find_string($string, $start = -1, $end = -1) { + if (($start == -1) or ($end == -1)) { + // find_string is called with only one parameter, set start end end + $start = 0; + $end = $this->total; + } + if (abs($start - $end) <= 1) { + // We're done, now we either found the string, or it doesn't exist + $txt = $this->get_original_string($start); + if ($string == $txt) + return $start; + else + return -1; + } else if ($start > $end) { + // start > end -> turn around and start over + return $this->find_string($string, $end, $start); + } else { + // Divide table in two parts + $half = (int)(($start + $end) / 2); + $cmp = strcmp($string, $this->get_original_string($half)); + if ($cmp == 0) + // string is exactly in the middle => return it + return $half; + else if ($cmp < 0) + // The string is in the upper half + return $this->find_string($string, $start, $half); + else + // The string is in the lower half + return $this->find_string($string, $half, $end); + } + } + + /** + * Translates a string + * + * @access public + * @param string string to be translated + * @return string translated string (or original, if not found) + */ + function translate($string) { + if ($this->short_circuit) + return $string; + $this->load_tables(); + + if ($this->enable_cache) { + // Caching enabled, get translated string from cache + if (array_key_exists($string, $this->cache_translations)) + return $this->cache_translations[$string]; + else + return $string; + } else { + // Caching not enabled, try to find string + $num = $this->find_string($string); + if ($num == -1) + return $string; + else + return $this->get_translation_string($num); + } + } + + /** + * Sanitize plural form expression for use in PHP eval call. + * + * @access private + * @return string sanitized plural form expression + */ + function sanitize_plural_expression($expr) { + // Get rid of disallowed characters. + $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); + + // Add parenthesis for tertiary '?' operator. + $expr .= ';'; + $res = ''; + $p = 0; + for ($i = 0; $i < strlen($expr); $i++) { + $ch = $expr[$i]; + switch ($ch) { + case '?': + $res .= ' ? ('; + $p++; + break; + case ':': + $res .= ') : ('; + break; + case ';': + $res .= str_repeat( ')', $p) . ';'; + $p = 0; + break; + default: + $res .= $ch; + } + } + return $res; + } + + /** + * Parse full PO header and extract only plural forms line. + * + * @access private + * @return string verbatim plural form header field + */ + function extract_plural_forms_header_from_po_header($header) { + if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) + $expr = $regs[2]; + else + $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; + return $expr; + } + + /** + * Get possible plural forms from MO header + * + * @access private + * @return string plural form header + */ + function get_plural_forms() { + // lets assume message number 0 is header + // this is true, right? + $this->load_tables(); + + // cache header field for plural forms + if (! is_string($this->pluralheader)) { + if ($this->enable_cache) { + $header = $this->cache_translations[""]; + } else { + $header = $this->get_translation_string(0); + } + $expr = $this->extract_plural_forms_header_from_po_header($header); + $this->pluralheader = $this->sanitize_plural_expression($expr); + } + return $this->pluralheader; + } + + /** + * Detects which plural form to take + * + * @access private + * @param n count + * @return int array index of the right plural form + */ + function select_string($n) { + $string = $this->get_plural_forms(); + $string = str_replace('nplurals',"\$total",$string); + $string = str_replace("n",$n,$string); + $string = str_replace('plural',"\$plural",$string); + + $total = 0; + $plural = 0; + + eval("$string"); + if ($plural >= $total) $plural = $total - 1; + return $plural; + } + + /** + * Plural version of gettext + * + * @access public + * @param string single + * @param string plural + * @param string number + * @return translated plural form + */ + function ngettext($single, $plural, $number) { + if ($this->short_circuit) { + if ($number != 1) + return $plural; + else + return $single; + } + + // find out the appropriate form + $select = $this->select_string($number); + + // this should contains all strings separated by NULLs + $key = $single . chr(0) . $plural; + + + if ($this->enable_cache) { + if (! array_key_exists($key, $this->cache_translations)) { + return ($number != 1) ? $plural : $single; + } else { + $result = $this->cache_translations[$key]; + $list = explode(chr(0), $result); + return $list[$select]; + } + } else { + $num = $this->find_string($key); + if ($num == -1) { + return ($number != 1) ? $plural : $single; + } else { + $result = $this->get_translation_string($num); + $list = explode(chr(0), $result); + return $list[$select]; + } + } + } + + function pgettext($context, $msgid) { + $key = $context . chr(4) . $msgid; + $ret = $this->translate($key); + if (strpos($ret, "\004") !== FALSE) { + return $msgid; + } else { + return $ret; + } + } + + function npgettext($context, $singular, $plural, $number) { + $key = $context . chr(4) . $singular; + $ret = $this->ngettext($key, $plural, $number); + if (strpos($ret, "\004") !== FALSE) { + return $singular; + } else { + return $ret; + } + + } +} + +?> diff --git a/ext/php-gettext/streams.php b/ext/php-gettext/streams.php new file mode 100644 index 0000000..afd0e6f --- /dev/null +++ b/ext/php-gettext/streams.php @@ -0,0 +1,167 @@ +. + + This file is part of PHP-gettext. + + PHP-gettext is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + PHP-gettext 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. + + You should have received a copy of the GNU General Public License + along with PHP-gettext; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + + // Simple class to wrap file streams, string streams, etc. + // seek is essential, and it should be byte stream +class StreamReader { + // should return a string [FIXME: perhaps return array of bytes?] + function read($bytes) { + return false; + } + + // should return new position + function seekto($position) { + return false; + } + + // returns current position + function currentpos() { + return false; + } + + // returns length of entire stream (limit for seekto()s) + function length() { + return false; + } +}; + +class StringReader { + var $_pos; + var $_str; + + function StringReader($str='') { + $this->_str = $str; + $this->_pos = 0; + } + + function read($bytes) { + $data = substr($this->_str, $this->_pos, $bytes); + $this->_pos += $bytes; + if (strlen($this->_str)<$this->_pos) + $this->_pos = strlen($this->_str); + + return $data; + } + + function seekto($pos) { + $this->_pos = $pos; + if (strlen($this->_str)<$this->_pos) + $this->_pos = strlen($this->_str); + return $this->_pos; + } + + function currentpos() { + return $this->_pos; + } + + function length() { + return strlen($this->_str); + } + +}; + + +class FileReader { + var $_pos; + var $_fd; + var $_length; + + function FileReader($filename) { + if (file_exists($filename)) { + + $this->_length=filesize($filename); + $this->_pos = 0; + $this->_fd = fopen($filename,'rb'); + if (!$this->_fd) { + $this->error = 3; // Cannot read file, probably permissions + return false; + } + } else { + $this->error = 2; // File doesn't exist + return false; + } + } + + function read($bytes) { + if ($bytes) { + fseek($this->_fd, $this->_pos); + + // PHP 5.1.1 does not read more than 8192 bytes in one fread() + // the discussions at PHP Bugs suggest it's the intended behaviour + $data = ''; + while ($bytes > 0) { + $chunk = fread($this->_fd, $bytes); + $data .= $chunk; + $bytes -= strlen($chunk); + } + $this->_pos = ftell($this->_fd); + + return $data; + } else return ''; + } + + function seekto($pos) { + fseek($this->_fd, $pos); + $this->_pos = ftell($this->_fd); + return $this->_pos; + } + + function currentpos() { + return $this->_pos; + } + + function length() { + return $this->_length; + } + + function close() { + fclose($this->_fd); + } + +}; + +// Preloads entire file in memory first, then creates a StringReader +// over it (it assumes knowledge of StringReader internals) +class CachedFileReader extends StringReader { + function CachedFileReader($filename) { + if (file_exists($filename)) { + + $length=filesize($filename); + $fd = fopen($filename,'rb'); + + if (!$fd) { + $this->error = 3; // Cannot read file, probably permissions + return false; + } + $this->_str = fread($fd, $length); + fclose($fd); + + } else { + $this->error = 2; // File doesn't exist + return false; + } + } +}; + + +?> diff --git a/ext/scriptaculous-js-1.8.2/MIT-LICENSE b/ext/scriptaculous-js-1.8.2/MIT-LICENSE index 3889631..87f7f53 100755 --- a/ext/scriptaculous-js-1.8.2/MIT-LICENSE +++ b/ext/scriptaculous-js-1.8.2/MIT-LICENSE @@ -1,20 +1,20 @@ -Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/ext/scriptaculous-js-1.8.2/README.rdoc b/ext/scriptaculous-js-1.8.2/README.rdoc index 21f8c8c..3f1398d 100755 --- a/ext/scriptaculous-js-1.8.2/README.rdoc +++ b/ext/scriptaculous-js-1.8.2/README.rdoc @@ -1,59 +1,59 @@ -== script.aculo.us web 2.0 javascript - -The Web is changing. The 30-year-old terminal-like technology it was originally -is gradually giving way to new ways of doing things. The power of AJAX allows -for rich user interaction without the trouble that has bugged traditional -web applications. - -Building upon the wonderful Prototype JavaScript library, script.aculo.us -provides you with some great additional ingredients to mix in. - -For more information, see http://script.aculo.us/ - -== What's new in this release? - -See the CHANGELOG file for information on what's new. - -You can follow http://twitter.com/scriptaculous if you want -to be updated as we fix bugs and add new features. - -== Installation/Usage - -script.aculo.us includes the Prototype JavaScript Framework -V1.6.0. You can use later versions, as they become available -(see http://prototypejs.org/). - -Put prototype.js, and the six files scriptaculous.js, -builder.js, effects.js, dragdrop.js, controls.js and slider.js -in a directory of your website, e.g. /javascripts. - -(The sound.js and unittest.js files are optional) - -Now, you can include the scripts by adding the following -tags to the HEAD section of your HTML pages: - - - - -scriptaculous.js will automatically load the other files of the -script.aculo.us distribution in, provided they are accessible -via the same path. - -See http://wiki.script.aculo.us/scriptaculous/show/Usage for detailed -usage instructions. - -== The distribution - -Besides the script.aculo.us files in src, there's a complete -test tree included which holds functional and unit tests for -script.aculo.us. - -If you need examples on how to implement things, the best place to -start is by opening test/run_functional_tests.html or -test/run_unit_tests.html in your browser, and looking at -the sources of the examples provided. - -== License - -script.aculo.us is licensed under the terms of the MIT License, +== script.aculo.us web 2.0 javascript + +The Web is changing. The 30-year-old terminal-like technology it was originally +is gradually giving way to new ways of doing things. The power of AJAX allows +for rich user interaction without the trouble that has bugged traditional +web applications. + +Building upon the wonderful Prototype JavaScript library, script.aculo.us +provides you with some great additional ingredients to mix in. + +For more information, see http://script.aculo.us/ + +== What's new in this release? + +See the CHANGELOG file for information on what's new. + +You can follow http://twitter.com/scriptaculous if you want +to be updated as we fix bugs and add new features. + +== Installation/Usage + +script.aculo.us includes the Prototype JavaScript Framework +V1.6.0. You can use later versions, as they become available +(see http://prototypejs.org/). + +Put prototype.js, and the six files scriptaculous.js, +builder.js, effects.js, dragdrop.js, controls.js and slider.js +in a directory of your website, e.g. /javascripts. + +(The sound.js and unittest.js files are optional) + +Now, you can include the scripts by adding the following +tags to the HEAD section of your HTML pages: + + + + +scriptaculous.js will automatically load the other files of the +script.aculo.us distribution in, provided they are accessible +via the same path. + +See http://wiki.script.aculo.us/scriptaculous/show/Usage for detailed +usage instructions. + +== The distribution + +Besides the script.aculo.us files in src, there's a complete +test tree included which holds functional and unit tests for +script.aculo.us. + +If you need examples on how to implement things, the best place to +start is by opening test/run_functional_tests.html or +test/run_unit_tests.html in your browser, and looking at +the sources of the examples provided. + +== License + +script.aculo.us is licensed under the terms of the MIT License, see the included MIT-LICENSE file. \ No newline at end of file diff --git a/ext/scriptaculous-js-1.8.2/lib/prototype.js b/ext/scriptaculous-js-1.8.2/lib/prototype.js index dfe8ab4..41bd8e3 100755 --- a/ext/scriptaculous-js-1.8.2/lib/prototype.js +++ b/ext/scriptaculous-js-1.8.2/lib/prototype.js @@ -1,4320 +1,4320 @@ -/* Prototype JavaScript framework, version 1.6.0.3 - * (c) 2005-2008 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://www.prototypejs.org/ - * - *--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.6.0.3', - - Browser: { - IE: !!(window.attachEvent && - navigator.userAgent.indexOf('Opera') === -1), - Opera: navigator.userAgent.indexOf('Opera') > -1, - WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, - Gecko: navigator.userAgent.indexOf('Gecko') > -1 && - navigator.userAgent.indexOf('KHTML') === -1, - MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) - }, - - BrowserFeatures: { - XPath: !!document.evaluate, - SelectorsAPI: !!document.querySelector, - ElementExtensions: !!window.HTMLElement, - SpecificElementExtensions: - document.createElement('div')['__proto__'] && - document.createElement('div')['__proto__'] !== - document.createElement('form')['__proto__'] - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -/* Based on Alex Arnell's inheritance implementation. */ -var Class = { - create: function() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - var subclass = function() { }; - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - - return klass; - } -}; - -Class.Methods = { - addMethods: function(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) - properties.push("toString", "valueOf"); - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value; - value = (function(m) { - return function() { return ancestor[m].apply(this, arguments) }; - })(property).wrap(method); - - value.valueOf = method.valueOf.bind(method); - value.toString = method.toString.bind(method); - } - this.prototype[property] = value; - } - - return this; - } -}; - -var Abstract = { }; - -Object.extend = function(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; -}; - -Object.extend(Object, { - inspect: function(object) { - try { - if (Object.isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - }, - - toJSON: function(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (Object.isElement(object)) return; - - var results = []; - for (var property in object) { - var value = Object.toJSON(object[property]); - if (!Object.isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - }, - - toQueryString: function(object) { - return $H(object).toQueryString(); - }, - - toHTML: function(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - }, - - keys: function(object) { - var keys = []; - for (var property in object) - keys.push(property); - return keys; - }, - - values: function(object) { - var values = []; - for (var property in object) - values.push(object[property]); - return values; - }, - - clone: function(object) { - return Object.extend({ }, object); - }, - - isElement: function(object) { - return !!(object && object.nodeType == 1); - }, - - isArray: function(object) { - return object != null && typeof object == "object" && - 'splice' in object && 'join' in object; - }, - - isHash: function(object) { - return object instanceof Hash; - }, - - isFunction: function(object) { - return typeof object == "function"; - }, - - isString: function(object) { - return typeof object == "string"; - }, - - isNumber: function(object) { - return typeof object == "number"; - }, - - isUndefined: function(object) { - return typeof object == "undefined"; - } -}); - -Object.extend(Function.prototype, { - argumentNames: function() { - var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1] - .replace(/\s+/g, '').split(','); - return names.length == 1 && !names[0] ? [] : names; - }, - - bind: function() { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } - }, - - bindAsEventListener: function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [event || window.event].concat(args)); - } - }, - - curry: function() { - if (!arguments.length) return this; - var __method = this, args = $A(arguments); - return function() { - return __method.apply(this, args.concat($A(arguments))); - } - }, - - delay: function() { - var __method = this, args = $A(arguments), timeout = args.shift() * 1000; - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - }, - - defer: function() { - var args = [0.01].concat($A(arguments)); - return this.delay.apply(this, args); - }, - - wrap: function(wrapper) { - var __method = this; - return function() { - return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); - } - }, - - methodize: function() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - return __method.apply(null, [this].concat($A(arguments))); - }; - } -}); - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - } finally { - this.currentlyExecuting = false; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, { - gsub: function(pattern, replacement) { - var result = '', source = this, match; - replacement = arguments.callee.prepareReplacement(replacement); - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - }, - - sub: function(pattern, replacement, count) { - replacement = this.gsub.prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - }, - - scan: function(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - }, - - truncate: function(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - }, - - strip: function() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - }, - - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(function(script) { return eval(script) }); - }, - - escapeHTML: function() { - var self = arguments.callee; - self.text.data = this; - return self.div.innerHTML; - }, - - unescapeHTML: function() { - var div = new Element('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? (div.childNodes.length > 1 ? - $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : - div.childNodes[0].nodeValue) : ''; - }, - - toQueryParams: function(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - }, - - toArray: function() { - return this.split(''); - }, - - succ: function() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - }, - - times: function(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - }, - - camelize: function() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - }, - - capitalize: function() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - }, - - underscore: function() { - return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); - }, - - dasherize: function() { - return this.gsub(/_/,'-'); - }, - - inspect: function(useDoubleQuotes) { - var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { - var character = String.specialChar[match[0]]; - return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - }, - - toJSON: function() { - return this.inspect(true); - }, - - unfilterJSON: function(filter) { - return this.sub(filter || Prototype.JSONFilter, '#{1}'); - }, - - isJSON: function() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - }, - - evalJSON: function(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - }, - - include: function(pattern) { - return this.indexOf(pattern) > -1; - }, - - startsWith: function(pattern) { - return this.indexOf(pattern) === 0; - }, - - endsWith: function(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - }, - - empty: function() { - return this == ''; - }, - - blank: function() { - return /^\s*$/.test(this); - }, - - interpolate: function(object, pattern) { - return new Template(this, pattern).evaluate(object); - } -}); - -if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { - escapeHTML: function() { - return this.replace(/&/g,'&').replace(//g,'>'); - }, - unescapeHTML: function() { - return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); - } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; -}; - -String.prototype.parseQuery = String.prototype.toQueryParams; - -Object.extend(String.prototype.escapeHTML, { - div: document.createElement('div'), - text: document.createTextNode('') -}); - -String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return ''; - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = { - each: function(iterator, context) { - var index = 0; - try { - this._each(function(value) { - iterator.call(context, value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - }, - - eachSlice: function(number, iterator, context) { - var index = -number, slices = [], array = this.toArray(); - if (number < 1) return array; - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - }, - - all: function(iterator, context) { - iterator = iterator || Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator, context) { - iterator = iterator || Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator.call(context, value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator.call(context, value, index)); - }); - return results; - }, - - detect: function(iterator, context) { - var result; - this.each(function(value, index) { - if (iterator.call(context, value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator, context) { - var results = []; - this.each(function(value, index) { - if (iterator.call(context, value, index)) - results.push(value); - }); - return results; - }, - - grep: function(filter, iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(filter); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator.call(context, value, index)); - }); - return results; - }, - - include: function(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inGroupsOf: function(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - }, - - inject: function(memo, iterator, context) { - this.each(function(value, index) { - memo = iterator.call(context, memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value >= result) - result = value; - }); - return result; - }, - - min: function(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value < result) - result = value; - }); - return result; - }, - - partition: function(iterator, context) { - iterator = iterator || Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator.call(context, value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator, context) { - var results = []; - this.each(function(value, index) { - if (!iterator.call(context, value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator, context) { - return this.map(function(value, index) { - return { - value: value, - criteria: iterator.call(context, value, index) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.map(); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - }, - - size: function() { - return this.toArray().length; - }, - - inspect: function() { - return '#'; - } -}; - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - filter: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray, - every: Enumerable.all, - some: Enumerable.any -}); -function $A(iterable) { - if (!iterable) return []; - if (iterable.toArray) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -if (Prototype.Browser.WebKit) { - $A = function(iterable) { - if (!iterable) return []; - // In Safari, only use the `toArray` method if it's not a NodeList. - // A NodeList is a function, has an function `item` property, and a numeric - // `length` property. Adapted from Google Doctype. - if (!(typeof iterable === 'function' && typeof iterable.length === - 'number' && typeof iterable.item === 'function') && iterable.toArray) - return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; - }; -} - -Array.from = $A; - -Object.extend(Array.prototype, Enumerable); - -if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(Object.isArray(value) ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - reduce: function() { - return this.length > 1 ? this : this[0]; - }, - - uniq: function(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - }, - - intersect: function(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - }, - - clone: function() { - return [].concat(this); - }, - - size: function() { - return this.length; - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - }, - - toJSON: function() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } -}); - -// use native browser JS 1.6 implementation if available -if (Object.isFunction(Array.prototype.forEach)) - Array.prototype._each = Array.prototype.forEach; - -if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; -}; - -if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; -}; - -Array.prototype.toArray = Array.prototype.clone; - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -if (Prototype.Browser.Opera){ - Array.prototype.concat = function() { - var array = []; - for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); - for (var i = 0, length = arguments.length; i < length; i++) { - if (Object.isArray(arguments[i])) { - for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) - array.push(arguments[i][j]); - } else { - array.push(arguments[i]); - } - } - return array; - }; -} -Object.extend(Number.prototype, { - toColorPart: function() { - return this.toPaddedString(2, 16); - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator, context) { - $R(0, this, true).each(iterator, context); - return this; - }, - - toPaddedString: function(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - }, - - toJSON: function() { - return isFinite(this) ? this.toString() : 'null'; - } -}); - -$w('abs round ceil floor').each(function(method){ - Number.prototype[method] = Math[method].methodize(); -}); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - return { - initialize: function(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - }, - - _each: function(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - set: function(key, value) { - return this._object[key] = value; - }, - - get: function(key) { - // simulating poorly supported hasOwnProperty - if (this._object[key] !== Object.prototype[key]) - return this._object[key]; - }, - - unset: function(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - }, - - toObject: function() { - return Object.clone(this._object); - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - index: function(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - }, - - merge: function(object) { - return this.clone().update(object); - }, - - update: function(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - }, - - toQueryString: function() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); - } else results.push(toQueryPair(key, values)); - return results; - }).join('&'); - }, - - inspect: function() { - return '#'; - }, - - toJSON: function() { - return Object.toJSON(this.toObject()); - }, - - clone: function() { - return new Hash(this); - } - } -})()); - -Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; -Hash.from = $H; -var ObjectRange = Class.create(Enumerable, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -}; - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); - -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); - -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - // simulate other verbs over post - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - // when GET, append parameters to URL - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - // user-defined headers - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - // avoid memory leak in MSIE: clean up - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - // DOM level 2 ECMAScript Language Binding - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - -(function() { - var element = this.Element; - this.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (Prototype.Browser.IE && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(this.Element, element || { }); - if (element) this.Element.prototype = element.prototype; -}).call(window); - -Element.cache = { }; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - hide: function(element) { - element = $(element); - element.style.display = 'none'; - return element; - }, - - show: function(element) { - element = $(element); - element.style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - content = Object.toHTML(content); - element.innerHTML = content.stripScripts(); - content.evalScripts.bind(content).defer(); - return element; - }, - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return $(element).recursivelyCollect('parentNode'); - }, - - descendants: function(element) { - return $(element).select("*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return $(element).recursivelyCollect('previousSibling'); - }, - - nextSiblings: function(element) { - return $(element).recursivelyCollect('nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return element.previousSiblings().reverse().concat(element.nextSiblings()); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = element.ancestors(); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? element.descendants()[expression] : - Element.select(element, expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = element.previousSiblings(); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = element.nextSiblings(); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - select: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element, args); - }, - - adjacent: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = element.readAttribute('id'), self = arguments.callee; - if (id) return id; - do { id = 'anonymous_element_' + self.counter++ } while ($(id)); - element.writeAttribute('id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return $(element).getDimensions().height; - }, - - getWidth: function(element) { - return $(element).getDimensions().width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!element.hasClassName(className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return element[element.hasClassName(className) ? - 'removeClassName' : 'addClassName'](className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (ancestor.contains) - return ancestor.contains(element) && ancestor !== element; - - while (element = element.parentNode) - if (element == ancestor) return true; - - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = element.cumulativeOffset(); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value || value == 'auto') { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = element.getStyle('display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (Prototype.Browser.Opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (element.getStyle('position') == 'absolute') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - var offsets = element.positionedOffset(); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (element.getStyle('position') == 'relative') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - // find page position of source - source = $(source); - var p = source.viewportOffset(); - - // find coordinate system to use - element = $(element); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(element, 'position') == 'absolute') { - parent = element.getOffsetParent(); - delta = parent.viewportOffset(); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Element.Methods.identify.counter = 1; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - // returns '0px' for hidden elements; we want it to return null - if (!Element.visible(element)) return null; - - // returns the border-box dimensions rather than the content-box - // dimensions, so we subtract padding and borders from the value - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - // IE doesn't report offsets correctly for static elements, so we change them - // to "relative" to get the values, then change them back. - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - // IE throws an error if element is not in document - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - // Trigger hasLayout on the offset parent so that IE6 reports - // accurate offsetTop and offsetLeft values for position: fixed. - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = { - read: { - names: { - 'class': 'className', - 'for': 'htmlFor' - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: function(element, attribute) { - attribute = element.getAttribute(attribute); - return attribute ? attribute.toString().slice(23, -2) : null; - }, - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - }; - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr, - src: v._getAttr, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - // Safari returns margins on body which is incorrect if the child is absolutely - // positioned. For performance reasons, redefine Element#cumulativeOffset for - // KHTML/WebKit only. - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if (Prototype.Browser.IE || Prototype.Browser.Opera) { - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements - Element.Methods.update = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - - content = Object.toHTML(content); - var tagName = element.tagName.toUpperCase(); - - if (tagName in Element._insertionTranslations.tags) { - $A(element.childNodes).each(function(node) { element.removeChild(node) }); - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { element.appendChild(node) }); - } - else element.innerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -if ('outerHTML' in document.createElement('div')) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['', '
      ', 1], - TBODY: ['', '
      ', 2], - TR: ['', '
      ', 3], - TD: ['
      ', '
      ', 4], - SELECT: ['', 1] - } -}; - -(function() { - Object.extend(this.tags, { - THEAD: this.tags.TBODY, - TFOOT: this.tags.TBODY, - TH: this.tags.TD - }); -}).call(Element._insertionTranslations); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return !!(node && node.specified); - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -if (!Prototype.BrowserFeatures.ElementExtensions && - document.createElement('div')['__proto__']) { - window.HTMLElement = { }; - window.HTMLElement.prototype = document.createElement('div')['__proto__']; - Prototype.BrowserFeatures.ElementExtensions = true; -} - -Element.extend = (function() { - if (Prototype.BrowserFeatures.SpecificElementExtensions) - return Prototype.K; - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || element._extendedByPrototype || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(), property, value; - - // extend methods for specific tags - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - for (property in methods) { - value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - // extend methods for all tags (Safari doesn't need this) - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - window[klass] = { }; - window[klass].prototype = document.createElement(tagName)['__proto__']; - return window[klass]; - } - - if (F.ElementExtensions) { - copy(Element.Methods, HTMLElement.prototype); - copy(Element.Methods.Simulated, HTMLElement.prototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - -document.viewport = { - getDimensions: function() { - var dimensions = { }, B = Prototype.Browser; - $w('width height').each(function(d) { - var D = d.capitalize(); - if (B.WebKit && !document.evaluate) { - // Safari <3.0 needs self.innerWidth/Height - dimensions[d] = self['inner' + D]; - } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { - // Opera <9.5 needs document.body.clientWidth/Height - dimensions[d] = document.body['client' + D] - } else { - dimensions[d] = document.documentElement['client' + D]; - } - }); - return dimensions; - }, - - getWidth: function() { - return this.getDimensions().width; - }, - - getHeight: function() { - return this.getDimensions().height; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); - } else { - this.mode = "normal"; - this.compileMatcher(); - } - - }, - - shouldUseXPath: function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - // Safari 3 chokes on :*-of-type and :empty - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - // XPath can't do namespaced attributes, nor can it read - // the "checked" property from DOM nodes - if ((/(\[[\w-]*?:|:checked)/).test(e)) - return false; - - return true; - }, - - shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; - - if (!Selector._div) Selector._div = new Element('div'); - - // Make sure the browser treats the selector as valid. Test on an - // isolated element to minimize cost of this check. - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; - } - - return true; - }, - - compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : - new Template(c[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.matcher.push("return h.unique(n);\n}"); - eval(this.matcher.join('\n')); - Selector._cache[this.expression] = this.matcher; - }, - - compileXPathMatcher: function() { - var e = this.expression, ps = Selector.patterns, - x = Selector.xpath, le, m; - - if (Selector._cache[e]) { - this.xpath = Selector._cache[e]; return; - } - - this.matcher = ['.//*']; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - if (m = e.match(ps[i])) { - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : - new Template(x[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } - - this.xpath = this.matcher.join(''); - Selector._cache[this.expression] = this.xpath; - }, - - findElements: function(root) { - root = root || document; - var e = this.expression, results; - - switch (this.mode) { - case 'selectorsAPI': - // querySelectorAll queries document-wide, then filters to descendants - // of the context element. That's not what we want. - // Add an explicit context to the selector if necessary. - if (root !== document) { - var oldId = root.id, id = $(root).identify(); - e = "#" + id + " " + e; - } - - results = $A(root.querySelectorAll(e)).map(Element.extend); - root.id = oldId; - - return results; - case 'xpath': - return document._getElementsByXPath(this.xpath, root); - default: - return this.matcher(root); - } - }, - - match: function(element) { - this.tokens = []; - - var e = this.expression, ps = Selector.patterns, as = Selector.assertions; - var le, p, m; - - while (e && le !== e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - // use the Selector.assertions methods unless the selector - // is too complex. - if (as[i]) { - this.tokens.push([i, Object.clone(m)]); - e = e.replace(m[0], ''); - } else { - // reluctantly do a document-wide search - // and look for a match in the array - return this.findElements(document).include(element); - } - } - } - } - - var match = true, name, matches; - for (var i = 0, token; token = this.tokens[i]; i++) { - name = token[0], matches = token[1]; - if (!Selector.assertions[name](element, matches)) { - match = false; break; - } - } - - return match; - }, - - toString: function() { - return this.expression; - }, - - inspect: function() { - return "#"; - } -}); - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in p) { - if (m = e.match(p[i])) { - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); - exclusion.push("(" + v.substring(1, v.length - 1) + ")"); - e = e.replace(m[0], ''); - break; - } - } - } - return "[not(" + exclusion.join(" and ") + ")]"; - }, - 'nth-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); - }, - 'nth-last-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); - }, - 'nth-of-type': function(m) { - return Selector.xpath.pseudos.nth("position() ", m); - }, - 'nth-last-of-type': function(m) { - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); - }, - 'first-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); - }, - 'last-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); - }, - 'only-of-type': function(m) { - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); - }, - nth: function(fragment, m) { - var mm, formula = m[6], predicate; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - if (mm = formula.match(/^(\d+)$/)) // digit only - return '[' + fragment + "= " + mm[1] + ']'; - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (mm[1] == "-") mm[1] = -1; - var a = mm[1] ? Number(mm[1]) : 1; - var b = mm[2] ? Number(mm[2]) : 0; - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + - "((#{fragment} - #{b}) div #{a} >= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: { - // combinators must be listed first - // (and descendant needs to be last combinator) - laterSibling: /^\s*~\s*/, - child: /^\s*>\s*/, - adjacent: /^\s*\+\s*/, - descendant: /^\s/, - - // selectors follow - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, - id: /^#([\w\-\*]+)(\b|$)/, - className: /^\.([\w\-\*]+)(\b|$)/, - pseudo: -/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, - attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ - }, - - // for Selector.match and Element#match - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - // UTILITY FUNCTIONS - // joins two collections - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - // marks an array of nodes for counting - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = undefined; - return nodes; - }, - - // mark each child node with its position (for nth calls) - // "ofType" flag indicates whether we're indexing for nth-of-type - // rather than nth-child - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - // filters out duplicates and extends all nodes - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (!(n = nodes[i])._countedByPrototype) { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - // COMBINATOR FUNCTIONS - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - // TOKEN FUNCTIONS - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - // fastlane for ordinary descendant combinators - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - if (!targetNode) return []; - if (!nodes && root == document) return [targetNode]; - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - // handles the an+b logic - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - // IE treats comments as element nodes - if (node.tagName == '!' || node.firstChild) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, - '$=': function(nv, v) { return nv.endsWith(v); }, - '*=': function(nv, v) { return nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + - '-').include('-' + (v || "").toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - // IE returns comment nodes on getElementsByTagName("*"). - // Filter them out. - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - }, - - // IE improperly serializes _countedByPrototype in (inner|outer)HTML. - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} -var Form = { - reset: function(form) { - $(form).reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - // a key is already present; construct an array of values - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - return $A($(form).getElementsByTagName('*')).inject([], - function(elements, child) { - if (Form.Element.Serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - } - ); - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !['button', 'reset', 'submit'].include(element.type))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, value) { - if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } - } - else opt.selected = value.include(currentValue); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - // extend element because hasAttribute may not be native - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) var Event = { }; - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: { }, - - relatedTarget: function(event) { - var element; - switch(event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } -}); - -Event.Methods = (function() { - var isButton; - - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - isButton = function(event, code) { - return event.button == buttonMap[code]; - }; - - } else if (Prototype.Browser.WebKit) { - isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - - } else { - isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - return { - isLeftClick: function(event) { return isButton(event, 0) }, - isMiddleClick: function(event) { return isButton(event, 1) }, - isRightClick: function(event) { return isButton(event, 2) }, - - element: function(event) { - event = Event.extend(event); - - var node = event.target, - type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - // Firefox screws up the "click" event when moving between radio buttons - // via arrow keys. It also screws up the "load" and "error" events on images, - // reporting the document as the target instead of the original image. - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; - return Element.extend(node); - }, - - findElement: function(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - }, - - pointer: function(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0, scrollTop: 0 }; - return { - x: event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)), - y: event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)) - }; - }, - - pointerX: function(event) { return Event.pointer(event).x }, - pointerY: function(event) { return Event.pointer(event).y }, - - stop: function(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - event.stopped = true; - } - }; -})(); - -Event.extend = (function() { - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return "[object Event]" } - }); - - return function(event) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - Object.extend(event, { - target: event.srcElement, - relatedTarget: Event.relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - return Object.extend(event, methods); - }; - - } else { - Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; - Object.extend(Event.prototype, methods); - return Prototype.K; - } -})(); - -Object.extend(Event, (function() { - var cache = Event.cache; - - function getEventID(element) { - if (element._prototypeEventID) return element._prototypeEventID[0]; - arguments.callee.id = arguments.callee.id || 1; - return element._prototypeEventID = [++arguments.callee.id]; - } - - function getDOMEventName(eventName) { - if (eventName && eventName.include(':')) return "dataavailable"; - return eventName; - } - - function getCacheForID(id) { - return cache[id] = cache[id] || { }; - } - - function getWrappersForEventName(id, eventName) { - var c = getCacheForID(id); - return c[eventName] = c[eventName] || []; - } - - function createWrapper(element, eventName, handler) { - var id = getEventID(element); - var c = getWrappersForEventName(id, eventName); - if (c.pluck("handler").include(handler)) return false; - - var wrapper = function(event) { - if (!Event || !Event.extend || - (event.eventName && event.eventName != eventName)) - return false; - - Event.extend(event); - handler.call(element, event); - }; - - wrapper.handler = handler; - c.push(wrapper); - return wrapper; - } - - function findWrapper(id, eventName, handler) { - var c = getWrappersForEventName(id, eventName); - return c.find(function(wrapper) { return wrapper.handler == handler }); - } - - function destroyWrapper(id, eventName, handler) { - var c = getCacheForID(id); - if (!c[eventName]) return false; - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); - } - - function destroyCache() { - for (var id in cache) - for (var eventName in cache[id]) - cache[id][eventName] = null; - } - - - // Internet Explorer needs to remove event handlers on page unload - // in order to avoid memory leaks. - if (window.attachEvent) { - window.attachEvent("onunload", destroyCache); - } - - // Safari has a dummy event handler on page unload so that it won't - // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" - // object when page is returned to via the back button using its bfcache. - if (Prototype.Browser.WebKit) { - window.addEventListener('unload', Prototype.emptyFunction, false); - } - - return { - observe: function(element, eventName, handler) { - element = $(element); - var name = getDOMEventName(eventName); - - var wrapper = createWrapper(element, eventName, handler); - if (!wrapper) return element; - - if (element.addEventListener) { - element.addEventListener(name, wrapper, false); - } else { - element.attachEvent("on" + name, wrapper); - } - - return element; - }, - - stopObserving: function(element, eventName, handler) { - element = $(element); - var id = getEventID(element), name = getDOMEventName(eventName); - - if (!handler && eventName) { - getWrappersForEventName(id, eventName).each(function(wrapper) { - element.stopObserving(eventName, wrapper.handler); - }); - return element; - - } else if (!eventName) { - Object.keys(getCacheForID(id)).each(function(eventName) { - element.stopObserving(eventName); - }); - return element; - } - - var wrapper = findWrapper(id, eventName, handler); - if (!wrapper) return element; - - if (element.removeEventListener) { - element.removeEventListener(name, wrapper, false); - } else { - element.detachEvent("on" + name, wrapper); - } - - destroyWrapper(id, eventName, handler); - - return element; - }, - - fire: function(element, eventName, memo) { - element = $(element); - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent("dataavailable", true, true); - } else { - event = document.createEventObject(); - event.eventType = "ondataavailable"; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) { - element.dispatchEvent(event); - } else { - element.fireEvent(event.eventType, event); - } - - return Event.extend(event); - } - }; -})()); - -Object.extend(Event, Event.Methods); - -Element.addMethods({ - fire: Event.fire, - observe: Event.observe, - stopObserving: Event.stopObserving -}); - -Object.extend(document, { - fire: Element.Methods.fire.methodize(), - observe: Element.Methods.observe.methodize(), - stopObserving: Element.Methods.stopObserving.methodize(), - loaded: false -}); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards and John Resig. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearInterval(timer); - document.fire("dom:loaded"); - document.loaded = true; - } - - if (document.addEventListener) { - if (Prototype.Browser.WebKit) { - timer = window.setInterval(function() { - if (/loaded|complete/.test(document.readyState)) - fireContentLoadedEvent(); - }, 0); - - Event.observe(window, "load", fireContentLoadedEvent); - - } else { - document.addEventListener("DOMContentLoaded", - fireContentLoadedEvent, false); - } - - } else { - document.write(" - +

      +

      + + + + + + + + + 'searchAccount', 'id'=>'ManasearchAccount'); + echo form_open('admin/search_account', $attributes); ?> + + + + + + + + 'searchCharacter', 'id'=>'ManasearchCharacter'); + echo form_open('admin/search_character', $attributes); ?> + + + + + + + +
      + An error occured:
      + +
      + + + + + + id="Manasubmit" title="" name="Manasearch"> +
      + + + + + + id="Manasubmit" title="" name="Manasearch"> +
      + +

      + +

      + + + + +

      +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      IDUsernameGroups
      getID() )) ?>">getID() ?>'.$searchstring.'', + $account->getUsername() ) ?>user->getUserLevelString($account->getLevel()) as $group ) + { + echo $group . ", "; + } + ?> + ( getLevel() ?> ) +
      getId() )) ?>">getId() ?>isOnline('img') ?> + getId() )) ?>"> + '.$searchstring.'', + $char->getName()) ?> + getOwnerId())) ?>">getUsername() ?>getGender('image') ?>getLevel() ?>getAttribute(Character::CHAR_ATTR_GP) ?>getMap()->getDescription() ?>
      +

      + + + + + + + + + + + diff --git a/system/application/views/admin/maintenance.php b/system/application/views/admin/maintenance.php index d9740b5..c1dfb62 100644 --- a/system/application/views/admin/maintenance.php +++ b/system/application/views/admin/maintenance.php @@ -1,208 +1,211 @@ -

      Cached data

      -

      Manaweb stores some temporary data like the provided maps in its own data -directory for fast and reliable access. If you made modifications to the -original data (maybe in manaserv), it is necessary to have manaweb to refresh its -stored data.

      - - 0 ) { ?> -

      - - 0) { ?> -
      - - For the following items, the image could not be found. Please update the - ./images/items directory of your manaweb installation.
      - - - -
      - -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0) { ?> - - - - -
      SubjectDescriptionValueActions
      - - - The file contains all maps provided by the map - server. Manaweb uses this file to show descriptions of the - character locations. - - - - - - - - - -   - -
      - - - The file contains all skills a character can gain. - Manaweb uses this file to show descriptions of the skills. - - - - - - - - - -   - -
      - - - The file contains all attributes a character can gain. - Manaweb uses this file to show descriptions of the attributes. - - - - - - - - - -   - -
      - item graphics - - The database table mana_items contains all known items - of The Mana Server. Use this function to copy all images provided - by the client data to a directory accessible to the webserver. - - - - - -   - -
      - Errorlogs - - CodeIgniter writes errors into daily rotating logfiles in a separate - directory. Here you can see how many logfiles have been written and - view these logfiles or simply clean up the directory. - - - Files: - 0) { ?> -
      - - Size: kB
      - - Oldest log:
      - Latest log: - -
      - 0) { ?> - - - - - - -   -
      - - - - - - - - - - - - - - - - - - - - - - -
      LogfileSizeDateAction
      kB"> - - - "> - - -
      -
      +

      +

      + + 0 ) { ?> +

      + + 0) { ?> +
      + + For the following items, the image could not be found. Please update the + ./images/items directory of your manaweb installation.
      + + + +
      + +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0) { ?> + + + + +
      + + + %s contains all maps provided by the map server. Manaweb uses this file to show descriptions of the character locations.'); + printf($format, XML_MAPS_FILE); + ?> + + + + + + + + + +   + +
      + + + %s contains all skills a character can gain. Manaweb uses this file to show descriptions of the skills.'); + printf($format, XML_SKILLS_FILE); + ?> + + + + + + + + + +   + +
      + + + %s contains all attributes a character can gain. Manaweb uses this file to show descriptions of the attributes.'); + printf($format, XML_ATTRIBUTES_FILE); + ?> + + + + + + + + + +   + +
      + + + config->item('tbl_name_items'); + printf($format, "" . $tblItems . ""); + ?> + + + + + +   + +
      + + + + + + + 0) { ?> +
      + +
      + +
      + + +
      + 0) { ?> + + + + + + +   +
      + + + + + + + + + + + + + + + + + + + + + + +
      kB"> + + + "> + + +
      +
      diff --git a/system/application/views/connector/onlineuser_csv.php b/system/application/views/connector/onlineuser_csv.php index a6dbcec..4091be7 100644 --- a/system/application/views/connector/onlineuser_csv.php +++ b/system/application/views/connector/onlineuser_csv.php @@ -1,23 +1,23 @@ - \ No newline at end of file diff --git a/system/application/views/connector/onlineuser_plain.php b/system/application/views/connector/onlineuser_plain.php index 1019afe..b6279d9 100644 --- a/system/application/views/connector/onlineuser_plain.php +++ b/system/application/views/connector/onlineuser_plain.php @@ -1,16 +1,16 @@ - \ No newline at end of file diff --git a/system/application/views/connector/onlineuser_xml.php b/system/application/views/connector/onlineuser_xml.php index 81c9b05..c2d7777 100644 --- a/system/application/views/connector/onlineuser_xml.php +++ b/system/application/views/connector/onlineuser_xml.php @@ -1,25 +1,25 @@ -"); - - foreach($users as $user) - { - $xuser = $xml->addChild("user"); - $xuser->addAttribute("name", $user['name']); - $xuser->addAttribute("gender", $user['gender']); - $xuser->addAttribute("map", $user['map_id']); - $xuser->addAttribute("login_timestamp", $user['login_date']); - $xuser->addAttribute("login_date", date("c", $user['login_date'])); - } - - echo $xml->asXML(); - return; - +"); + + foreach($users as $user) + { + $xuser = $xml->addChild("user"); + $xuser->addAttribute("name", $user['name']); + $xuser->addAttribute("gender", $user['gender']); + $xuser->addAttribute("map", $user['map_id']); + $xuser->addAttribute("login_timestamp", $user['login_date']); + $xuser->addAttribute("login_date", date("c", $user['login_date'])); + } + + echo $xml->asXML(); + return; + ?> \ No newline at end of file diff --git a/system/application/views/index.html b/system/application/views/index.html index c942a79..065d2da 100644 --- a/system/application/views/index.html +++ b/system/application/views/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 403 Forbidden + + + +

      Directory access is forbidden.

      + + \ No newline at end of file diff --git a/system/application/views/layout/footer.php b/system/application/views/layout/footer.php index 681042f..30337b8 100644 --- a/system/application/views/layout/footer.php +++ b/system/application/views/layout/footer.php @@ -1,19 +1,19 @@ -getThemeInfo(); - $theme =& $themeprovider->getTheme(); -?> - - afterContent() ?> - - - - - - - +getThemeInfo(); + $theme =& $themeprovider->getTheme(); +?> + + afterContent() ?> + + + + + + + diff --git a/system/application/views/layout/header.php b/system/application/views/layout/header.php index b641299..a8580f8 100644 --- a/system/application/views/layout/header.php +++ b/system/application/views/layout/header.php @@ -1,122 +1,122 @@ -getThemeInfo(); - $theme =& $themeprovider->getTheme(); - -echo ""; ?> - - - - The Mana Source Account Manager - - - - - - - - - - - - - - - - - - - - beforeLogo(); - echo $theme->Logo(); - echo $theme->afterLogo(); - ?> - - - - - beforeNavigationBar(); - - // TODO: do this with plugins... - $nb = new NavigationBox( 'navigation.mana.main', '' ); - - $nb->addNavigationItem( new NavigationItem('navigation.mana.main.itemslist', - _("Itemslist"), site_url('itemslist') ) ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.main.serverstats', - _("Statistics"), site_url('statistics') ) ); - - $navigation->addNavbox($nb, 10); - - // user nav box - $nb = new NavigationBox( 'navigation.mana.usermenu', _("User menu") ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.usermenu.myaccount', - _("My Account"), site_url('myaccount') ) ); - if (isset($user_menu) ) - { - foreach( $user_menu as $link ) - { - $nb->addNavigationItem( new NavigationItem('navigation.mana.usermenu.' . $link['name'], - $link['name'], $link['url'] ) ); - } - } - $navigation->addNavbox($nb, 20); - - // char navbox - if (isset($character_menu)) - { - $nb = new NavigationBox( 'navigation.mana.character', $character_menu->getName() ); - - $nb->addNavigationItem( new NavigationItem('navigation.mana.character.index', - _("Character sheet"), site_url("charcontroller/".$character_menu->getId() )) ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.character.skills', - _("Skills"), site_url("charcontroller/".$character_menu->getId()."/skills" )) ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.character.inventory', - _("Inventory"), site_url("charcontroller/".$character_menu->getId()."/inventory" )) ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.character.guilds', - _("Parties & Guilds"), site_url("charcontroller/".$character_menu->getId()."/guilds" )) ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.character.admin', - _("Administration"), site_url("charcontroller/".$character_menu->getId()."/admin" )) ); - - $navigation->addNavbox($nb, 30); - } - - // administration menu - if ( isset($user_menu) && $this->user->isAdmin() ) - { - $nb = new NavigationBox( 'navigation.mana.administration', _("Admin Interface") ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.administration.index', - _("Admin Interface"), site_url("admin" )) ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.administration.maintenance', - _("Maintenance"), site_url("admin/maintenance" )) ); - $navigation->addNavbox($nb, 90); - } - - - // manabay -- this will be the first more complex plugin i thing... - $nb = new NavigationBox( 'navigation.mana.manabay', _("Manabay") ); - $nb->addNavigationItem( new NavigationItem('navigation.mana.manabay.auctions', - _("Auctions"), site_url('manabay') ) ); - - $navigation->addNavbox($nb, 100); - - // - - - - - - - - - - - - - - foreach( $navigation->getNavboxes() as $box ) - { - echo $theme->beforeNavigationBox(); - echo $theme->NavigationBox($box); - echo $theme->afterNavigationBox(); - } - ?> - - - afterNavigationBar() ?> - beforeContent() ?> - title($page_title) ?> - - +getThemeInfo(); + $theme =& $themeprovider->getTheme(); + +echo ""; ?> + + + + The Mana Source Account Manager + + + + + + + + + + + + + + + + + + + + beforeLogo(); + echo $theme->Logo(); + echo $theme->afterLogo(); + ?> + + + + + beforeNavigationBar(); + + // TODO: do this with plugins... + $nb = new NavigationBox( 'navigation.mana.main', '' ); + + $nb->addNavigationItem( new NavigationItem('navigation.mana.main.itemslist', + T_("Itemslist"), site_url('itemslist') ) ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.main.serverstats', + T_("Statistics"), site_url('statistics') ) ); + + $navigation->addNavbox($nb, 10); + + // user nav box + $nb = new NavigationBox( 'navigation.mana.usermenu', _("User menu") ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.usermenu.myaccount', + _("My Account"), site_url('myaccount') ) ); + if (isset($user_menu) ) + { + foreach( $user_menu as $link ) + { + $nb->addNavigationItem( new NavigationItem('navigation.mana.usermenu.' . $link['name'], + $link['name'], $link['url'] ) ); + } + } + $navigation->addNavbox($nb, 20); + + // char navbox + if (isset($character_menu)) + { + $nb = new NavigationBox( 'navigation.mana.character', $character_menu->getName() ); + + $nb->addNavigationItem( new NavigationItem('navigation.mana.character.index', + _("Character sheet"), site_url("charcontroller/".$character_menu->getId() )) ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.character.skills', + _("Skills"), site_url("charcontroller/".$character_menu->getId()."/skills" )) ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.character.inventory', + _("Inventory"), site_url("charcontroller/".$character_menu->getId()."/inventory" )) ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.character.guilds', + _("Parties & Guilds"), site_url("charcontroller/".$character_menu->getId()."/guilds" )) ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.character.admin', + _("Administration"), site_url("charcontroller/".$character_menu->getId()."/admin" )) ); + + $navigation->addNavbox($nb, 30); + } + + // administration menu + if ( isset($user_menu) && $this->user->isAdmin() ) + { + $nb = new NavigationBox( 'navigation.mana.administration', _("Admin Interface") ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.administration.index', + _("Admin Interface"), site_url("admin" )) ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.administration.maintenance', + _("Maintenance"), site_url("admin/maintenance" )) ); + $navigation->addNavbox($nb, 90); + } + + + // manabay -- this will be the first more complex plugin i thing... + $nb = new NavigationBox( 'navigation.mana.manabay', _("Manabay") ); + $nb->addNavigationItem( new NavigationItem('navigation.mana.manabay.auctions', + _("Auctions"), site_url('manabay') ) ); + + $navigation->addNavbox($nb, 100); + + // - - - - - - - - - - - - + + foreach( $navigation->getNavboxes() as $box ) + { + echo $theme->beforeNavigationBox(); + echo $theme->NavigationBox($box); + echo $theme->afterNavigationBox(); + } + ?> + + + afterNavigationBar() ?> + beforeContent() ?> + title($page_title) ?> + + diff --git a/system/application/views/mailtemplates/request_pwd_change.php b/system/application/views/mailtemplates/request_pwd_change.php index 6723fe4..70c37a0 100644 --- a/system/application/views/mailtemplates/request_pwd_change.php +++ b/system/application/views/mailtemplates/request_pwd_change.php @@ -1,13 +1,13 @@ -Hello {username}, - -you`ve requested to change your account password for The Mana Server. -Click the link above, or copy and paste it in your browser to reach the -"change password" form. - -{password_link} - -If you`ve never requested to change your password just ignore this mail. - - -Have a nice day! -your The Mana Source dev team. +Hello {username}, + +you`ve requested to change your account password for The Mana Server. +Click the link above, or copy and paste it in your browser to reach the +"change password" form. + +{password_link} + +If you`ve never requested to change your password just ignore this mail. + + +Have a nice day! +your The Mana Source dev team. diff --git a/system/application/views/manabay/auction_list.php b/system/application/views/manabay/auction_list.php index 7ad18d0..54f78a8 100644 --- a/system/application/views/manabay/auction_list.php +++ b/system/application/views/manabay/auction_list.php @@ -1,89 +1,89 @@ -

      Next 10 auctions to finish

      - - -

      Currently, there are no open auctions.

      - - - - - - - - - - - - - getDuration(); - $item = $auction->getItem(); - ?> - - - - - - - - - -
      ItemSellerEndtimeBidsPrice
      getId() ) ?>"> - name ?> -
      description ?> -
      getSeller()->getName(); ?>getEndtime()); ?>
      - -
      getAuctionStats(Auction::AUCTION_BID_COUNT); ?>getAuctionStats(Auction::AUCTION_MAX_PRICE); ?> gp
      - - - -

      Search auctions by category

      - - - - - - - -
      - Weapons
      - -
      - Clothes
      - -
      - Others
      - -
      - - -

      ManaBay statistics

      - +

      + + +

      + + + + + + + + + + + + + getDuration(); + $item = $auction->getItem(); + ?> + + + + + + + + + +
      getId() ) ?>"> + name ?> +
      description ?> +
      getSeller()->getName(); ?>getEndtime()); ?>
      + +
      getAuctionStats(Auction::AUCTION_BID_COUNT); ?>getAuctionStats(Auction::AUCTION_MAX_PRICE); ?> gp
      + + + +

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

      + diff --git a/system/application/views/manaweb/accountmanager/change_mailaddress_form.php b/system/application/views/manaweb/accountmanager/change_mailaddress_form.php index 10545c4..b155c61 100644 --- a/system/application/views/manaweb/accountmanager/change_mailaddress_form.php +++ b/system/application/views/manaweb/accountmanager/change_mailaddress_form.php @@ -1,93 +1,93 @@ - -
      -

      -

      - - 'changeEmail', 'id'=>'ManaChangeEmail'); - echo form_open('accountmanager/changemailaddress', $attributes); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - Something was wrong with your new mailaddress:
      - -
      - -
      - - - -
      - - - -
      - - - -
      - - - -
      - - -
      + +
      +

      +

      + + 'changeEmail', 'id'=>'ManaChangeEmail'); + echo form_open('accountmanager/changemailaddress', $attributes); ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + +
      + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + +
      diff --git a/system/application/views/manaweb/character.php b/system/application/views/manaweb/character.php index 0692a5d..1ac80dc 100644 --- a/system/application/views/manaweb/character.php +++ b/system/application/views/manaweb/character.php @@ -1,177 +1,177 @@ -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - : - - getName() ?> - - : - - - getAttribute(Character::CHAR_ATTR_STRENGTH) ?> - - - - - - - - - - - - - - - - - - - - - - - - -
      - - -
      - - -
      - - - - -
      - - -
      - -
      - : - - getGender('image') ?> - - : - - - getAttribute(Character::CHAR_ATTR_AGILITY) ?> - -
      - : - - getLevel() ?> - - : - - - getAttribute(Character::CHAR_ATTR_DEXTERITY) ?> - -
      - : - - getAttribute(Character::CHAR_ATTR_GP) ?> - - : - - - getAttribute(Character::CHAR_ATTR_VITALITY) ?> - -
      - : - - - getMap()->getDescription(); ?> - - - : - - - getAttribute(Character::CHAR_ATTR_INTELLIGENCE) ?> - -
      -   - - : - - - getAttribute(Character::CHAR_ATTR_WILLPOWER) ?> - -
      - +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + : + + getName() ?> + + : + + + getAttribute(Character::CHAR_ATTR_STRENGTH) ?> + + + + + + + + + + + + + + + + + + + + + + + + +
      + + +
      + + +
      + + + + +
      + + +
      + +
      + : + + getGender('image') ?> + + : + + + getAttribute(Character::CHAR_ATTR_AGILITY) ?> + +
      + : + + getLevel() ?> + + : + + + getAttribute(Character::CHAR_ATTR_DEXTERITY) ?> + +
      + : + + getAttribute(Character::CHAR_ATTR_GP) ?> + + : + + + getAttribute(Character::CHAR_ATTR_VITALITY) ?> + +
      + : + + + getMap()->getDescription(); ?> + + + : + + + getAttribute(Character::CHAR_ATTR_INTELLIGENCE) ?> + +
      +   + + : + + + getAttribute(Character::CHAR_ATTR_WILLPOWER) ?> + +
      + diff --git a/system/application/views/manaweb/character_administration.php b/system/application/views/manaweb/character_administration.php index 7e11c66..9a3705f 100644 --- a/system/application/views/manaweb/character_administration.php +++ b/system/application/views/manaweb/character_administration.php @@ -1,3 +1,3 @@ -

      - -

      Sorry, this feature is not yet supported.

      \ No newline at end of file +

      + +

      \ No newline at end of file diff --git a/system/application/views/manaweb/character_guilds.php b/system/application/views/manaweb/character_guilds.php index 0fc2243..1ba1652 100644 --- a/system/application/views/manaweb/character_guilds.php +++ b/system/application/views/manaweb/character_guilds.php @@ -1,37 +1,37 @@ -

      -isGuildMember()) - { // the char is member in at least one guild... -?> - - - - - - - - - getGuilds() as $guild) { ?> - - - - - - -
      getId() ?> - - getName() ?> - - countMembers() ?>
      - - -

      - -

      - +

      +isGuildMember()) + { // the char is member in at least one guild... +?> + + + + + + + + + getGuilds() as $guild) { ?> + + + + + + +
      getId() ?> + + getName() ?> + + countMembers() ?>
      + + +

      + +

      + diff --git a/system/application/views/manaweb/character_inventory.php b/system/application/views/manaweb/character_inventory.php index cceafe7..3bef1f9 100644 --- a/system/application/views/manaweb/character_inventory.php +++ b/system/application/views/manaweb/character_inventory.php @@ -1,73 +1,73 @@ -getInventory()->getWeight('inventory'); - $weight_equ = $char->getInventory()->getWeight('equipment'); - $weight_all = $weight_inv + $weight_equ; - $weight_max = $char->getMaximumWeight(); - $weight_pct = intval(100/$weight_max*$weight_all); - - // tiny checks - if ($weight_pct < 0) - { - $weight_pct = 0; - } - if ($weight_pct > 100) - { - $weight_pct = 100; - } -?> -
      - Your current load: of -
      - -

      - -

      Sorry, this feature is not yet supported.

      - -

      - - - - - - - - - - - getInventory()->getInventory() as $item) { ?> - - - - - - - - - - - - - - - - - - - - - - - -
      ItemDescriptionEffectAmountWeight
      name ?>description ?>effect ?>amount ?>weight) * intval($item->amount) ?>
      - - -
      - Weight of your equipped items: - - + -
      - Total weight of all your items: - - -
      +getInventory()->getWeight('inventory'); + $weight_equ = $char->getInventory()->getWeight('equipment'); + $weight_all = $weight_inv + $weight_equ; + $weight_max = $char->getMaximumWeight(); + $weight_pct = intval(100/$weight_max*$weight_all); + + // tiny checks + if ($weight_pct < 0) + { + $weight_pct = 0; + } + if ($weight_pct > 100) + { + $weight_pct = 100; + } +?> +
      + Your current load: of +
      + +

      + +

      + +

      + + + + + + + + + + + getInventory()->getInventory() as $item) { ?> + + + + + + + + + + + + + + + + + + + + + + + +
      name ?>description ?>effect ?>amount ?>weight) * intval($item->amount) ?>
      + + +
      + + + + +
      + + + +
      diff --git a/system/application/views/manaweb/character_skills.php b/system/application/views/manaweb/character_skills.php index 11c6d29..4fe6b40 100644 --- a/system/application/views/manaweb/character_skills.php +++ b/system/application/views/manaweb/character_skills.php @@ -1,46 +1,46 @@ -getSkillsets() as $skillset) -{ - echo "\n

      " . $skillset->getName() . "

      \n"; - echo ""; - - // loop over all skins in the skinset - foreach ($skillset->getSkills() as $skill) - { - $skillinfo = $char->getSkillInfo($skill->getId()); - if (true || $skillinfo['level'] > 0) - { - echo " - - - - - "; - } // skill level > 0 - } // foreach skill - - echo "
      "; - - if ($skill->hasIcon()) { - echo " - getImage($skill->getIcon(), Imageprovider::MANADATA_DIRECTORY) - ."\">"; - } - echo " - - ". - $skill->getName() . ": - - ".$skillinfo['level']." - - ".$skillinfo['exp_delta']." / ". - $skillinfo['exp_max_delta']." -
      "; - to_the_top(); - -} // foreach skillset - -?> +getSkillsets() as $skillset) +{ + echo "\n

      " . $skillset->getName() . "

      \n"; + echo ""; + + // loop over all skins in the skinset + foreach ($skillset->getSkills() as $skill) + { + $skillinfo = $char->getSkillInfo($skill->getId()); + if (true || $skillinfo['level'] > 0) + { + echo " + + + + + "; + } // skill level > 0 + } // foreach skill + + echo "
      "; + + if ($skill->hasIcon()) { + echo " + getImage($skill->getIcon(), Imageprovider::MANADATA_DIRECTORY) + ."\">"; + } + echo " + + ". + $skill->getName() . ": + + ".$skillinfo['level']." + + ".$skillinfo['exp_delta']." / ". + $skillinfo['exp_max_delta']." +
      "; + to_the_top(); + +} // foreach skillset + +?> diff --git a/system/application/views/manaweb/delete_account.php b/system/application/views/manaweb/delete_account.php index 0439522..8b2ec5b 100644 --- a/system/application/views/manaweb/delete_account.php +++ b/system/application/views/manaweb/delete_account.php @@ -1,23 +1,23 @@ -

      Attention!

      - -

      Do you really want to delete your account? Remember: this action -cannot be undone!

      - - 'deleteAccount', 'id' => 'ManaDeleteAccount'); - echo form_open('accountmanager/execute_delete', $attributes); ?> - - - - - -
      - - -
      - +

      Attention!

      + +

      Do you really want to delete your account? Remember: this action +cannot be undone!

      + + 'deleteAccount', 'id' => 'ManaDeleteAccount'); + echo form_open('accountmanager/execute_delete', $attributes); ?> + + + + + +
      + + +
      + diff --git a/system/application/views/manaweb/delete_account_done.php b/system/application/views/manaweb/delete_account_done.php index bb7e953..1a569fc 100644 --- a/system/application/views/manaweb/delete_account_done.php +++ b/system/application/views/manaweb/delete_account_done.php @@ -1,4 +1,4 @@ -

      Done!

      - -

      Your account has been deleted!

      - +

      Done!

      + +

      Your account has been deleted!

      + diff --git a/system/application/views/manaweb/guilds/show_guild.php b/system/application/views/manaweb/guilds/show_guild.php index 8c27e54..7b7376f 100644 --- a/system/application/views/manaweb/guilds/show_guild.php +++ b/system/application/views/manaweb/guilds/show_guild.php @@ -1,42 +1,42 @@ - -

      - - - - - - - - - getMembers() as $member) { - $char = $member['character']; - - if ($char->getOwnerId() == $user->getId()) - { - $isOwn = true; - } - else - { - $isOwn = false; - } - ?> - - - - - - - - - -
      CharacterLevelGenderMapPlayer
      - getId() )) ?>'> - getName() ?> - - - isOnline('image') ?> - getLevel() ?>getGender('image') ?>getMap()->getDescription() ?> - '> - getUsername() ?> - -
      + +

      + + + + + + + + + getMembers() as $member) { + $char = $member['character']; + + if ($char->getOwnerId() == $user->getId()) + { + $isOwn = true; + } + else + { + $isOwn = false; + } + ?> + + + + + + + + + +
      CharacterLevelGenderMapPlayer
      + getId() )) ?>'> + getName() ?> + + + isOnline('image') ?> + getLevel() ?>getGender('image') ?>getMap()->getDescription() ?> + '> + getUsername() ?> + +
      diff --git a/system/application/views/manaweb/item_list.php b/system/application/views/manaweb/item_list.php index b532cef..cc8db64 100644 --- a/system/application/views/manaweb/item_list.php +++ b/system/application/views/manaweb/item_list.php @@ -1,127 +1,127 @@ -

      Item dictionary

      - - 'ManasearchItemForm', 'id'=>'ManasearchItemForm'); - echo form_open('itemslist/search_item', $attributes); ?> - - - - - - - - - - - - - - - - - - - - - - - -
      You can search an item by its name...
      - Sorry, your search returns no rows. -
      - - - - - -
      - - - -
      -
      ... or by its category:
      - Weapons
      -
        -
      • ">one handed - (getItemsPerCat( Inventory::ITEM_TYPE_ONEHAND ) ?>)
      • -
      • ">two handed - (getItemsPerCat( Inventory::ITEM_TYPE_TWOHAND ) ?>)
      • -
      • ">ammunition - (getItemsPerCat( Inventory::ITEM_TYPE_AMMO ) ?>)
      • -
      • ">shields - (getItemsPerCat( Inventory::ITEM_TYPE_SHIELD ) ?>)
      • -
      -
      - Clothes
      -
        -
      • ">arms - (getItemsPerCat( Inventory::ITEM_TYPE_ARMS ) ?>)
      • -
      • ">feet - (getItemsPerCat( Inventory::ITEM_TYPE_FEET ) ?>)
      • -
      • ">head - (getItemsPerCat( Inventory::ITEM_TYPE_HEAD ) ?>)
      • -
      • ">legs - (getItemsPerCat( Inventory::ITEM_TYPE_LEGS ) ?>)
      • -
      • ">torso - (getItemsPerCat( Inventory::ITEM_TYPE_TORSO ) ?>)
      • -
      -
      - Others
      -
        -
      • ">rings - (getItemsPerCat( Inventory::ITEM_TYPE_RING ) ?>)
      • -
      • ">generics - (getItemsPerCat( Inventory::ITEM_TYPE_GENERIC ) ?>)
      • -
      • ">usable - (getItemsPerCat( Inventory::ITEM_TYPE_USABLE ) ?>)
      • -
      -
      - - - - - - - - - - - - - - - - - - - -
      NameWeightEffect
      - '.$searchstring.'', - $item->name); - } - else - { - echo $item->name; - } ?>
      - description ?> -
      weight ?>effect ?>
      - - - - +

      + + 'ManasearchItemForm', 'id'=>'ManasearchItemForm'); + echo form_open('itemslist/search_item', $attributes); ?> + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + + + + + +
      + + + +
      +
      :
      +
      +
        +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_ONEHAND ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_TWOHAND ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_AMMO ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_SHIELD ) ?>)
      • +
      +
      +
      +
        +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_ARMS ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_FEET ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_HEAD ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_LEGS ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_TORSO ) ?>)
      • +
      +
      +
      +
        +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_RING ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_GENERIC ) ?>)
      • +
      • "> + (getItemsPerCat( Inventory::ITEM_TYPE_USABLE ) ?>)
      • +
      +
      + + + + + + + + + + + + + + + + + + + +
      + '.$searchstring.'', + $item->name); + } + else + { + echo $item->name; + } ?>
      + description ?> +
      weight ?>effect ?>
      + + + + diff --git a/system/application/views/manaweb/login_form.php b/system/application/views/manaweb/login_form.php index bf60a34..cdf0706 100644 --- a/system/application/views/manaweb/login_form.php +++ b/system/application/views/manaweb/login_form.php @@ -1,89 +1,77 @@ -

      Login to The Mana Server Account Manager

      - - 'loginForm', 'id' => 'ManaLoginForm'); - echo form_open('myaccount/login', $attributes); ?> - - -

      - -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - Something was wrong with your login:
      - validation->error_string; ?> -
      - - - -
      - - - -
      - - - -
      - - - -
      - - -
      - » Lost your password? -
      - - - - - +

      + + 'loginForm', 'id' => 'ManaLoginForm'); + echo form_open('myaccount/login', $attributes); ?> + + +

      + +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + validation->error_string; ?> +
      + + + +
      + + + +
      + + + +
      + + +
      + » +
      + + + + + diff --git a/system/application/views/manaweb/lost_password.php b/system/application/views/manaweb/lost_password.php index 052d7fe..6d3c18b 100644 --- a/system/application/views/manaweb/lost_password.php +++ b/system/application/views/manaweb/lost_password.php @@ -1,59 +1,59 @@ -

      Lost your password?

      - -

      If you`ve forgotton your password, don`t panic! You can reset your password - with this simple form. Please provide your username and the mailaddress you - registered with. After that you will receive a email containing a link - where you can change your password. -

      - - - 'lostPassword', 'id' => 'ManaResetPassword'); - echo form_open('myaccount/resetpassword', $attributes); ?> - - - - - - - - - - - - - - - - - - -
      - Something was wrong with your data:
      - validation->error_string; ?> -
      - - - -
      - - - -
      - - -
      - - - - - +

      Lost your password?

      + +

      If you`ve forgotton your password, don`t panic! You can reset your password + with this simple form. Please provide your username and the mailaddress you + registered with. After that you will receive a email containing a link + where you can change your password. +

      + + + 'lostPassword', 'id' => 'ManaResetPassword'); + echo form_open('myaccount/resetpassword', $attributes); ?> + + + + + + + + + + + + + + + + + + +
      + Something was wrong with your data:
      + validation->error_string; ?> +
      + + + +
      + + + +
      + + +
      + + + + + diff --git a/system/application/views/manaweb/lost_password_change.php b/system/application/views/manaweb/lost_password_change.php index b72eeaa..c6de9a5 100644 --- a/system/application/views/manaweb/lost_password_change.php +++ b/system/application/views/manaweb/lost_password_change.php @@ -1,87 +1,87 @@ -

      Hello , now change your password!

      - -

      - Please type in a new password for your account and retype it to be sure you - have no typo in it. -

      - - -'changePassword', 'id'=>'ManaChangePassword'); - echo form_open('myaccount/setnewpassword', $attributes); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -
      - Something was wrong with your new password:
      - validation->error_string; ?> -
      - Username: - - -
      - Activation key: - - -
      - - - -
      - - - -
      - - - - - -
      - - - -

      - Note: The activation key will be invalidated after you`ve - set your new password. If you plan to change it again sometimes, you have - to request anouther activation key. -

      - - - +

      Hello , now change your password!

      + +

      + Please type in a new password for your account and retype it to be sure you + have no typo in it. +

      + + +'changePassword', 'id'=>'ManaChangePassword'); + echo form_open('myaccount/setnewpassword', $attributes); ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + Something was wrong with your new password:
      + validation->error_string; ?> +
      + Username: + + +
      + Activation key: + + +
      + + + +
      + + + +
      + + + + + +
      + + + +

      + Note: The activation key will be invalidated after you`ve + set your new password. If you plan to change it again sometimes, you have + to request anouther activation key. +

      + + + diff --git a/system/application/views/manaweb/lost_password_mailsent.php b/system/application/views/manaweb/lost_password_mailsent.php index d0f712e..045cf14 100644 --- a/system/application/views/manaweb/lost_password_mailsent.php +++ b/system/application/views/manaweb/lost_password_mailsent.php @@ -1,17 +1,17 @@ -

      Hello

      - -

      A email was sent to your given address . -Please follow the instructions in this mail to finally change your password. -

      - -

      -You should be redirected to the login page in a few seconds. If not, click -here:

      -» back to the Login page -

      - - +

      Hello

      + +

      A email was sent to your given address . +Please follow the instructions in this mail to finally change your password. +

      + +

      +You should be redirected to the login page in a few seconds. If not, click +here:

      +» back to the Login page +

      + + diff --git a/system/application/views/manaweb/lost_password_wrong_key.php b/system/application/views/manaweb/lost_password_wrong_key.php index 85f6211..bf6862c 100644 --- a/system/application/views/manaweb/lost_password_wrong_key.php +++ b/system/application/views/manaweb/lost_password_wrong_key.php @@ -1,11 +1,11 @@ -

      Request for a new password.

      - -

      -

      - Sorry, either the username or the secret key is not valid. Please - check if you`ve copied the complete url from your mail and pasted - to your browser. -
      -

      - - +

      Request for a new password.

      + +

      +

      + Sorry, either the username or the secret key is not valid. Please + check if you`ve copied the complete url from your mail and pasted + to your browser. +
      +

      + + diff --git a/system/application/views/manaweb/server_statistics.php b/system/application/views/manaweb/server_statistics.php index 5b33634..c0b7047 100644 --- a/system/application/views/manaweb/server_statistics.php +++ b/system/application/views/manaweb/server_statistics.php @@ -1,97 +1,102 @@ -

      Server Statistics

      -

      -Currently there are -individual Characters on , played by - players. -The characters founded - guilds.
      -All characters form a purchasing power of - . -

      - - - - - - - - - - - - - - - - - - -
      - Number of players: - - - - - - -
      - Number of characters: - - - - -
      - Number of guilds: - - - - -
      - -

      The top 10 Guilds

      - -

      Sorry, there are currently no guilds founded.

      - - - - - - - - - - - - - - -
      GuildMembers
      .NAME ?>MEMBERS ?>
      - - - - -

      The top 10 Characters

      - -

      Sorry, there are currently no characters alive.

      - - - - - - - - - - - - - - - - -
      CharacterPlayerLevel
      NAME ?>USERNAME ?>LEVEL ?>
      - +

      +

      + +
      + +
      + +

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

      + +

      + + + + + + + + + + + + + + +
      .NAME ?>MEMBERS ?>
      + + + + +

      + +

      Sorry, there are currently no characters alive.

      + + + + + + + + + + + + + + + + +
      NAME ?>USERNAME ?>LEVEL ?>
      + diff --git a/system/application/views/manaweb/settings.php b/system/application/views/manaweb/settings.php index 5ea79db..851c1d8 100644 --- a/system/application/views/manaweb/settings.php +++ b/system/application/views/manaweb/settings.php @@ -1,157 +1,157 @@ -

      - - - -

      -

      - - - - - - - - - +

      + + + +

      +

      + + + + + + + + + diff --git a/system/application/views/manaweb/user_home.php b/system/application/views/manaweb/user_home.php index 4f4ec5a..022c41d 100644 --- a/system/application/views/manaweb/user_home.php +++ b/system/application/views/manaweb/user_home.php @@ -1,72 +1,68 @@ -

      Welcome getUsername() ?>!

      - -

      From this page you can manage several options of your account. Also you can - get current statistics of you characters. Please choose one option - below: - -

        -
      • View your character stats
      • -
      • Change your password
      • -
      • Change your mailaddress
      • -
      -

      - -

      -user->isBanned()) - { - echo "Your account is banned until ". date(lang('date_time_format') .". ", - $this->user->isBanned()); - } - else - { - echo "You are a member of the following access groups: -

        "; - foreach ($groups as $group) - { - echo "
      • $group
      • "; - } - echo "
      "; - } -?> -This account is registered since user->getRegistrationDate()) ?>. Your last login was - user->getLastLogin()) ?>. -

      - - -

      Character overview

      - -user->hasCharacters()){ ?> - -

      Here you see a summary of all your characters. Click on the name -of one to see its details.

      - - - - - - - - - -user->getCharacters() as $char){ ?> - - - - - - - - -
      NameLevelGenderMoneyMap
      getName() ?>getLevel() ?>getGender('image') ?>getAttribute(Character::CHAR_ATTR_GP) ?>getMap()->getDescription() ?>
      - - -

      You currently don't have any characters. This is is a little uncommon, - but never mind: You can create one with the Mana client.

      - - - +

      getUsername() ?>!

      + +

      + +

        +
      • +
      • +
      • +
      +

      + +

      +user->isBanned()) + { + echo "Your account is banned until ". date(T_('date_time_format') .". ", + $this->user->isBanned()); + } + else + { + echo T_("You are a member of the following access groups:"); + echo "

        "; + foreach ($groups as $group) + { + echo "
      • $group
      • "; + } + echo "
      "; + } +?> + user->getRegistrationDate()) ?>. + user->getLastLogin()) ?>. +

      + + +

      + +user->hasCharacters()){ ?> + +

      + + + + + + + + + +user->getCharacters() as $char){ ?> + + + + + + + + +
      getName() ?>getLevel() ?>getGender('image') ?>getAttribute(Character::CHAR_ATTR_GP) ?>getMap()->getDescription() ?>
      + + +

      + + + diff --git a/system/cache/index.html b/system/cache/index.html index c942a79..065d2da 100644 --- a/system/cache/index.html +++ b/system/cache/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 403 Forbidden + + + +

      Directory access is forbidden.

      + + \ No newline at end of file diff --git a/system/codeigniter/Base4.php b/system/codeigniter/Base4.php index e48e14c..0a814c8 100644 --- a/system/codeigniter/Base4.php +++ b/system/codeigniter/Base4.php @@ -1,69 +1,69 @@ -load->library('email') to instantiate - * classes that can then be used within controllers as $this->email->send() - * - * PHP 4 also has trouble referencing the CI super object within application - * constructors since objects do not exist until the class is fully - * instantiated. Basically PHP 4 sucks... - * - * Since PHP 5 doesn't suffer from this problem so we load one of - * two files based on the version of PHP being run. - * - * @package CodeIgniter - * @subpackage codeigniter - * @category front-controller - * @author ExpressionEngine Dev Team - * @link http://codeigniter.com/user_guide/ - */ - class CI_Base extends CI_Loader { - - function CI_Base() - { - // This allows syntax like $this->load->foo() to work - parent::CI_Loader(); - $this->load =& $this; - - // This allows resources used within controller constructors to work - global $OBJ; - $OBJ = $this->load; // Do NOT use a reference. - } -} - -function &get_instance() -{ - global $CI, $OBJ; - - if (is_object($CI)) - { - return $CI; - } - - return $OBJ->load; -} - - -/* End of file Base4.php */ +load->library('email') to instantiate + * classes that can then be used within controllers as $this->email->send() + * + * PHP 4 also has trouble referencing the CI super object within application + * constructors since objects do not exist until the class is fully + * instantiated. Basically PHP 4 sucks... + * + * Since PHP 5 doesn't suffer from this problem so we load one of + * two files based on the version of PHP being run. + * + * @package CodeIgniter + * @subpackage codeigniter + * @category front-controller + * @author ExpressionEngine Dev Team + * @link http://codeigniter.com/user_guide/ + */ + class CI_Base extends CI_Loader { + + function CI_Base() + { + // This allows syntax like $this->load->foo() to work + parent::CI_Loader(); + $this->load =& $this; + + // This allows resources used within controller constructors to work + global $OBJ; + $OBJ = $this->load; // Do NOT use a reference. + } +} + +function &get_instance() +{ + global $CI, $OBJ; + + if (is_object($CI)) + { + return $CI; + } + + return $OBJ->load; +} + + +/* End of file Base4.php */ /* Location: ./system/codeigniter/Base4.php */ \ No newline at end of file diff --git a/system/codeigniter/Base5.php b/system/codeigniter/Base5.php index 5d944ae..b5ab8ac 100644 --- a/system/codeigniter/Base5.php +++ b/system/codeigniter/Base5.php @@ -1,56 +1,56 @@ -mark('total_execution_time_start'); -$BM->mark('loading_time_base_classes_start'); - -/* - * ------------------------------------------------------ - * Instantiate the hooks class - * ------------------------------------------------------ - */ - -$EXT =& load_class('Hooks'); - -/* - * ------------------------------------------------------ - * Is there a "pre_system" hook? - * ------------------------------------------------------ - */ -$EXT->_call_hook('pre_system'); - -/* - * ------------------------------------------------------ - * Instantiate the base classes - * ------------------------------------------------------ - */ - -$CFG =& load_class('Config'); -$URI =& load_class('URI'); -$RTR =& load_class('Router'); -$OUT =& load_class('Output'); - -/* - * ------------------------------------------------------ - * 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 remaining base classes - * ------------------------------------------------------ - */ - -$IN =& load_class('Input'); -$LANG =& load_class('Language'); - -/* - * ------------------------------------------------------ - * Load the app controller and local controller - * ------------------------------------------------------ - * - * Note: Due to the poor object handling in PHP 4 we'll - * conditionally load different versions of the base - * class. Retaining PHP 4 compatibility requires a bit of a hack. - * - * Note: The Loader class needs to be included first - * - */ -if ( ! is_php('5.0.0')) -{ - load_class('Loader', FALSE); - require(BASEPATH.'codeigniter/Base4'.EXT); -} -else -{ - require(BASEPATH.'codeigniter/Base5'.EXT); -} - -// Load the base controller class -load_class('Controller', FALSE); - -// Load the local application controller -// Note: The Router class automatically validates the controller path. 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().EXT)) -{ - 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().EXT); - -// 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 $method == 'controller' - OR strncmp($method, '_', 1) == 0 - OR in_array(strtolower($method), array_map('strtolower', get_class_methods('Controller'))) - ) -{ - show_404("{$class}/{$method}"); -} - -/* - * ------------------------------------------------------ - * Is there a "pre_controller" hook? - * ------------------------------------------------------ - */ -$EXT->_call_hook('pre_controller'); - -/* - * ------------------------------------------------------ - * Instantiate the controller and call requested method - * ------------------------------------------------------ - */ - -// Mark a start point so we can benchmark the controller -$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); - -$CI = new $class(); - -// Is this a scaffolding request? -if ($RTR->scaffolding_request === TRUE) -{ - if ($EXT->_call_hook('scaffolding_override') === FALSE) - { - $CI->_ci_scaffolding(); - } -} -else -{ - /* - * ------------------------------------------------------ - * Is there a "post_controller_constructor" hook? - * ------------------------------------------------------ - */ - $EXT->_call_hook('post_controller_constructor'); - - // Is there a "remap" function? - if (method_exists($CI, '_remap')) - { - $CI->_remap($method); - } - 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)))) - { - 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 */ +mark('total_execution_time_start'); +$BM->mark('loading_time_base_classes_start'); + +/* + * ------------------------------------------------------ + * Instantiate the hooks class + * ------------------------------------------------------ + */ + +$EXT =& load_class('Hooks'); + +/* + * ------------------------------------------------------ + * Is there a "pre_system" hook? + * ------------------------------------------------------ + */ +$EXT->_call_hook('pre_system'); + +/* + * ------------------------------------------------------ + * Instantiate the base classes + * ------------------------------------------------------ + */ + +$CFG =& load_class('Config'); +$URI =& load_class('URI'); +$RTR =& load_class('Router'); +$OUT =& load_class('Output'); + +/* + * ------------------------------------------------------ + * 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 remaining base classes + * ------------------------------------------------------ + */ + +$IN =& load_class('Input'); +$LANG =& load_class('Language'); + +/* + * ------------------------------------------------------ + * Load the app controller and local controller + * ------------------------------------------------------ + * + * Note: Due to the poor object handling in PHP 4 we'll + * conditionally load different versions of the base + * class. Retaining PHP 4 compatibility requires a bit of a hack. + * + * Note: The Loader class needs to be included first + * + */ +if ( ! is_php('5.0.0')) +{ + load_class('Loader', FALSE); + require(BASEPATH.'codeigniter/Base4'.EXT); +} +else +{ + require(BASEPATH.'codeigniter/Base5'.EXT); +} + +// Load the base controller class +load_class('Controller', FALSE); + +// Load the local application controller +// Note: The Router class automatically validates the controller path. 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().EXT)) +{ + 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().EXT); + +// 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 $method == 'controller' + OR strncmp($method, '_', 1) == 0 + OR in_array(strtolower($method), array_map('strtolower', get_class_methods('Controller'))) + ) +{ + show_404("{$class}/{$method}"); +} + +/* + * ------------------------------------------------------ + * Is there a "pre_controller" hook? + * ------------------------------------------------------ + */ +$EXT->_call_hook('pre_controller'); + +/* + * ------------------------------------------------------ + * Instantiate the controller and call requested method + * ------------------------------------------------------ + */ + +// Mark a start point so we can benchmark the controller +$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_start'); + +$CI = new $class(); + +// Is this a scaffolding request? +if ($RTR->scaffolding_request === TRUE) +{ + if ($EXT->_call_hook('scaffolding_override') === FALSE) + { + $CI->_ci_scaffolding(); + } +} +else +{ + /* + * ------------------------------------------------------ + * Is there a "post_controller_constructor" hook? + * ------------------------------------------------------ + */ + $EXT->_call_hook('post_controller_constructor'); + + // Is there a "remap" function? + if (method_exists($CI, '_remap')) + { + $CI->_remap($method); + } + 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)))) + { + 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/codeigniter/CodeIgniter.php */ \ No newline at end of file diff --git a/system/codeigniter/Common.php b/system/codeigniter/Common.php index dc277b8..2eaa048 100644 --- a/system/codeigniter/Common.php +++ b/system/codeigniter/Common.php @@ -1,421 +1,421 @@ - 5 -* we'll set a static variable. -* -* @access public -* @param string -* @return bool -*/ -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 - */ -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(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 (($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 bool optional flag that lets classes get loaded but not instantiated -* @return object -*/ -function &load_class($class, $instantiate = TRUE) -{ - static $objects = array(); - - // Does the class exist? If so, we're done... - if (isset($objects[$class])) - { - return $objects[$class]; - } - - // If the requested class does not exist in the application/libraries - // folder we'll load the native class from the system/libraries folder. - if (file_exists(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT)) - { - require(BASEPATH.'libraries/'.$class.EXT); - require(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT); - $is_subclass = TRUE; - } - else - { - if (file_exists(APPPATH.'libraries/'.$class.EXT)) - { - require(APPPATH.'libraries/'.$class.EXT); - $is_subclass = FALSE; - } - else - { - require(BASEPATH.'libraries/'.$class.EXT); - $is_subclass = FALSE; - } - } - - if ($instantiate == FALSE) - { - $objects[$class] = TRUE; - return $objects[$class]; - } - - if ($is_subclass == TRUE) - { - $name = config_item('subclass_prefix').$class; - - $objects[$class] =& instantiate_class(new $name()); - return $objects[$class]; - } - - $name = ($class != 'Controller') ? 'CI_'.$class : $class; - - $objects[$class] =& instantiate_class(new $name()); - return $objects[$class]; -} - -/** - * Instantiate Class - * - * Returns a new class object by reference, used by load_class() and the DB class. - * Required to retain PHP 4 compatibility and also not make PHP 5.3 cry. - * - * Use: $obj =& instantiate_class(new Foo()); - * - * @access public - * @param object - * @return object - */ -function &instantiate_class(&$class_object) -{ - return $class_object; -} - -/** -* Loads the main config.php file -* -* @access private -* @return array -*/ -function &get_config() -{ - static $main_conf; - - if ( ! isset($main_conf)) - { - if ( ! file_exists(APPPATH.'config/config'.EXT)) - { - exit('The configuration file config'.EXT.' does not exist.'); - } - - require(APPPATH.'config/config'.EXT); - - if ( ! isset($config) OR ! is_array($config)) - { - exit('Your config file does not appear to be formatted correctly.'); - } - - $main_conf[0] =& $config; - } - return $main_conf[0]; -} - -/** -* Gets a config item -* -* @access public -* @return mixed -*/ -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 -*/ -function show_error($message, $status_code = 500) -{ - $error =& load_class('Exceptions'); - echo $error->show_error('An Error Was Encountered', $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 -*/ -function show_404($page = '') -{ - $error =& load_class('Exceptions'); - $error->show_404($page); - 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 -*/ -function log_message($level = 'error', $message, $php_error = FALSE) -{ - static $LOG; - - $config =& get_config(); - if ($config['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 - */ -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 permit -* PHP errors to be logged in our own log files since we 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 -*/ -function _exception_handler($severity, $message, $filepath, $line) -{ - // We don't bother with "strict" notices since they will fill up - // the log file with 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'); - - // 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... - $config =& get_config(); - if ($config['log_threshold'] == 0) - { - return; - } - - $error->log_exception($severity, $message, $filepath, $line); -} - - - -/* End of file Common.php */ + 5 +* we'll set a static variable. +* +* @access public +* @param string +* @return bool +*/ +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 + */ +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(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 (($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 bool optional flag that lets classes get loaded but not instantiated +* @return object +*/ +function &load_class($class, $instantiate = TRUE) +{ + static $objects = array(); + + // Does the class exist? If so, we're done... + if (isset($objects[$class])) + { + return $objects[$class]; + } + + // If the requested class does not exist in the application/libraries + // folder we'll load the native class from the system/libraries folder. + if (file_exists(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT)) + { + require(BASEPATH.'libraries/'.$class.EXT); + require(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT); + $is_subclass = TRUE; + } + else + { + if (file_exists(APPPATH.'libraries/'.$class.EXT)) + { + require(APPPATH.'libraries/'.$class.EXT); + $is_subclass = FALSE; + } + else + { + require(BASEPATH.'libraries/'.$class.EXT); + $is_subclass = FALSE; + } + } + + if ($instantiate == FALSE) + { + $objects[$class] = TRUE; + return $objects[$class]; + } + + if ($is_subclass == TRUE) + { + $name = config_item('subclass_prefix').$class; + + $objects[$class] =& instantiate_class(new $name()); + return $objects[$class]; + } + + $name = ($class != 'Controller') ? 'CI_'.$class : $class; + + $objects[$class] =& instantiate_class(new $name()); + return $objects[$class]; +} + +/** + * Instantiate Class + * + * Returns a new class object by reference, used by load_class() and the DB class. + * Required to retain PHP 4 compatibility and also not make PHP 5.3 cry. + * + * Use: $obj =& instantiate_class(new Foo()); + * + * @access public + * @param object + * @return object + */ +function &instantiate_class(&$class_object) +{ + return $class_object; +} + +/** +* Loads the main config.php file +* +* @access private +* @return array +*/ +function &get_config() +{ + static $main_conf; + + if ( ! isset($main_conf)) + { + if ( ! file_exists(APPPATH.'config/config'.EXT)) + { + exit('The configuration file config'.EXT.' does not exist.'); + } + + require(APPPATH.'config/config'.EXT); + + if ( ! isset($config) OR ! is_array($config)) + { + exit('Your config file does not appear to be formatted correctly.'); + } + + $main_conf[0] =& $config; + } + return $main_conf[0]; +} + +/** +* Gets a config item +* +* @access public +* @return mixed +*/ +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 +*/ +function show_error($message, $status_code = 500) +{ + $error =& load_class('Exceptions'); + echo $error->show_error(T_('An Error Was Encountered'), $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 +*/ +function show_404($page = '') +{ + $error =& load_class('Exceptions'); + $error->show_404($page); + 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 +*/ +function log_message($level = 'error', $message, $php_error = FALSE) +{ + static $LOG; + + $config =& get_config(); + if ($config['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 + */ +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 permit +* PHP errors to be logged in our own log files since we 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 +*/ +function _exception_handler($severity, $message, $filepath, $line) +{ + // We don't bother with "strict" notices since they will fill up + // the log file with 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'); + + // 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... + $config =& get_config(); + if ($config['log_threshold'] == 0) + { + return; + } + + $error->log_exception($severity, $message, $filepath, $line); +} + + + +/* End of file Common.php */ /* Location: ./system/codeigniter/Common.php */ \ No newline at end of file diff --git a/system/codeigniter/Compat.php b/system/codeigniter/Compat.php index 2c22fd3..7b5bc7e 100644 --- a/system/codeigniter/Compat.php +++ b/system/codeigniter/Compat.php @@ -1,93 +1,93 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 403 Forbidden + + + +

      Directory access is forbidden.

      + + \ No newline at end of file diff --git a/system/database/DB.php b/system/database/DB.php index c0e9011..ee2eb00 100644 --- a/system/database/DB.php +++ b/system/database/DB.php @@ -1,146 +1,144 @@ - $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 == TRUE) - { - $active_record = TRUE; - } - - require_once(BASEPATH.'database/DB_driver'.EXT); - - if ( ! isset($active_record) OR $active_record == TRUE) - { - require_once(BASEPATH.'database/DB_active_rec'.EXT); - - 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'.EXT); - - // Instantiate the DB adapter - $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; - $DB =& instantiate_class(new $driver($params)); - - if ($DB->autoinit == TRUE) - { - $DB->initialize(); - } - - return $DB; -} - - - -/* End of file DB.php */ + $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 == TRUE) + { + $active_record = TRUE; + } + + require_once(BASEPATH.'database/DB_driver'.EXT); + + if ( ! isset($active_record) OR $active_record == TRUE) + { + require_once(BASEPATH.'database/DB_active_rec'.EXT); + + 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'.EXT); + + // Instantiate the DB adapter + $driver = 'CI_DB_'.$params['dbdriver'].'_driver'; + $DB =& instantiate_class(new $driver($params)); + + if ($DB->autoinit == TRUE) + { + $DB->initialize(); + } + + 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 index b9676c6..542244b 100644 --- a/system/database/DB_active_rec.php +++ b/system/database/DB_active_rec.php @@ -1,1820 +1,1820 @@ -_protect_identifiers = $escape; - } - - if (is_string($select)) - { - $select = explode(',', $select); - } - - foreach ($select as $val) - { - $val = trim($val); - - if ($val != '') - { - $this->ar_select[] = $val; - - if ($this->ar_caching === TRUE) - { - $this->ar_cache_select[] = $val; - $this->ar_cache_exists[] = 'select'; - } - } - } - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Select Max - * - * Generates a SELECT MAX(field) portion of a query - * - * @access public - * @param string the field - * @param string an alias - * @return object - */ - 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 - * - * @access public - * @param string the field - * @param string an alias - * @return object - */ - 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 - * - * @access public - * @param string the field - * @param string an alias - * @return object - */ - 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 - * - * @access public - * @param string the field - * @param string an alias - * @return object - */ - 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() - * - * @access public - * @param string the field - * @param string an alias - * @return object - */ - 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 - * - * @access private - * @param string - * @return string - */ - 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 - * - * @access public - * @param bool - * @return object - */ - function distinct($val = TRUE) - { - $this->ar_distinct = (is_bool($val)) ? $val : TRUE; - return $this; - } - - // -------------------------------------------------------------------- - - /** - * From - * - * Generates the FROM portion of the query - * - * @access public - * @param mixed can be a string or array - * @return object - */ - 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 - * - * @access public - * @param string - * @param string the join condition - * @param string the type of join - * @return object - */ - 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 - * - * @access public - * @param mixed - * @param mixed - * @return object - */ - 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 - * - * @access public - * @param mixed - * @param mixed - * @return object - */ - function or_where($key, $value = NULL, $escape = TRUE) - { - return $this->_where($key, $value, 'OR ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * orwhere() is an alias of or_where() - * this function is here for backwards compatibility, as - * orwhere() has been deprecated - */ - function orwhere($key, $value = NULL, $escape = TRUE) - { - return $this->or_where($key, $value, $escape); - } - - // -------------------------------------------------------------------- - - /** - * Where - * - * Called by where() or orwhere() - * - * @access private - * @param mixed - * @param mixed - * @param string - * @return object - */ - 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 - * - * @access public - * @param string The field to search - * @param array The values searched on - * @return object - */ - 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 - * - * @access public - * @param string The field to search - * @param array The values searched on - * @return object - */ - 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 - * - * @access public - * @param string The field to search - * @param array The values searched on - * @return object - */ - 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 - * - * @access public - * @param string The field to search - * @param array The values searched on - * @return object - */ - 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 - * - * @access public - * @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 - */ - 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 - * - * @access public - * @param mixed - * @param mixed - * @return object - */ - 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 - * - * @access public - * @param mixed - * @param mixed - * @return object - */ - 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 - * - * @access public - * @param mixed - * @param mixed - * @return object - */ - 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 - * - * @access public - * @param mixed - * @param mixed - * @return object - */ - function or_not_like($field, $match = '', $side = 'both') - { - return $this->_like($field, $match, 'OR ', $side, 'NOT'); - } - - // -------------------------------------------------------------------- - - /** - * orlike() is an alias of or_like() - * this function is here for backwards compatibility, as - * orlike() has been deprecated - */ - function orlike($field, $match = '', $side = 'both') - { - return $this->or_like($field, $match, $side); - } - - // -------------------------------------------------------------------- - - /** - * Like - * - * Called by like() or orlike() - * - * @access private - * @param mixed - * @param mixed - * @param string - * @return object - */ - 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 == '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_char); - } - - $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 - * - * @access public - * @param string - * @return object - */ - 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; - } - - // -------------------------------------------------------------------- - - /** - * groupby() is an alias of group_by() - * this function is here for backwards compatibility, as - * groupby() has been deprecated - */ - function groupby($by) - { - return $this->group_by($by); - } - - // -------------------------------------------------------------------- - - /** - * Sets the HAVING value - * - * Separates multiple calls with AND - * - * @access public - * @param string - * @param string - * @return object - */ - function having($key, $value = '', $escape = TRUE) - { - return $this->_having($key, $value, 'AND ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * orhaving() is an alias of or_having() - * this function is here for backwards compatibility, as - * orhaving() has been deprecated - */ - - function orhaving($key, $value = '', $escape = TRUE) - { - return $this->or_having($key, $value, $escape); - } - // -------------------------------------------------------------------- - - /** - * Sets the OR HAVING value - * - * Separates multiple calls with OR - * - * @access public - * @param string - * @param string - * @return object - */ - function or_having($key, $value = '', $escape = TRUE) - { - return $this->_having($key, $value, 'OR ', $escape); - } - - // -------------------------------------------------------------------- - - /** - * Sets the HAVING values - * - * Called by having() or or_having() - * - * @access private - * @param string - * @param string - * @return object - */ - 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_str($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 - * - * @access public - * @param string - * @param string direction: asc or desc - * @return object - */ - 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; - } - - // -------------------------------------------------------------------- - - /** - * orderby() is an alias of order_by() - * this function is here for backwards compatibility, as - * orderby() has been deprecated - */ - function orderby($orderby, $direction = '') - { - return $this->order_by($orderby, $direction); - } - - // -------------------------------------------------------------------- - - /** - * Sets the LIMIT value - * - * @access public - * @param integer the limit value - * @param integer the offset value - * @return object - */ - function limit($value, $offset = '') - { - $this->ar_limit = $value; - - if ($offset != '') - { - $this->ar_offset = $offset; - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Sets the OFFSET value - * - * @access public - * @param integer the offset value - * @return object - */ - function offset($offset) - { - $this->ar_offset = $offset; - return $this; - } - - // -------------------------------------------------------------------- - - /** - * The "set" function. Allows key/value pairs to be set for inserting or updating - * - * @access public - * @param mixed - * @param string - * @param boolean - * @return object - */ - 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)] = $this->escape($v); - } - } - - return $this; - } - - // -------------------------------------------------------------------- - - /** - * Get - * - * Compiles the select statement based on the other functions called - * and runs the query - * - * @access public - * @param string the table - * @param string the limit clause - * @param string the offset clause - * @return object - */ - 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. - * - * @access public - * @param string - * @return string - */ - 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 $row->numrows; - } - - // -------------------------------------------------------------------- - - /** - * Get_Where - * - * Allows the where clause, limit and offset to be added directly - * - * @access public - * @param string the where clause - * @param string the limit clause - * @param string the offset clause - * @return object - */ - 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; - } - - // -------------------------------------------------------------------- - - /** - * getwhere() is an alias of get_where() - * this function is here for backwards compatibility, as - * getwhere() has been deprecated - */ - function getwhere($table = '', $where = null, $limit = null, $offset = null) - { - return $this->get_where($table, $where, $limit, $offset); - } - - // -------------------------------------------------------------------- - - /** - * Insert - * - * Compiles an insert string and runs the query - * - * @access public - * @param string the table to retrieve the results from - * @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); - } - - // -------------------------------------------------------------------- - - /** - * Update - * - * Compiles an update string and runs the query - * - * @access public - * @param string the table to retrieve the results from - * @param array an associative array of update values - * @param mixed the where clause - * @return object - */ - 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); - } - - // -------------------------------------------------------------------- - - /** - * Empty Table - * - * Compiles a delete string and runs "DELETE FROM table" - * - * @access public - * @param string the table to empty - * @return object - */ - 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" - * - * @access public - * @param string the table to truncate - * @return object - */ - 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 - * - * @access public - * @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 - */ - 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 - * - * @access public - * @param string the table - * @return string - */ - function dbprefix($table = '') - { - if ($table == '') - { - $this->display_error('db_table_name_required'); - } - - return $this->dbprefix.$table; - } - - // -------------------------------------------------------------------- - - /** - * Track Aliases - * - * Used to track SQL statements written with aliased tables. - * - * @access private - * @param string The table to inspect - * @return string - */ - 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('/ AS /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. - * - * @access private - * @return string - */ - 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) - { - $this->ar_select[$key] = $this->_protect_identifiers($val); - } - - $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 .= "\n"; - - $sql .= "WHERE "; - } - - $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 - * - * @access public - * @param object - * @return array - */ - 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' && $key != '_ci_scaffolding' && $key != '_ci_scaff_table') - { - $array[$key] = $val; - } - } - - return $array; - } - - // -------------------------------------------------------------------- - - /** - * Start Cache - * - * Starts AR caching - * - * @access public - * @return void - */ - function start_cache() - { - $this->ar_caching = TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Stop Cache - * - * Stops AR caching - * - * @access public - * @return void - */ - function stop_cache() - { - $this->ar_caching = FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Flush Cache - * - * Empties the AR cache - * - * @access public - * @return void - */ - 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() - ) - ); - } - - // -------------------------------------------------------------------- - - /** - * Merge Cache - * - * When called, this function merges any cached AR arrays with - * locally called ones. - * - * @access private - * @return void - */ - 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); - } - } - - // -------------------------------------------------------------------- - - /** - * Resets the active record values. Called by the get() function - * - * @access private - * @param array An array of fields to reset - * @return void - */ - 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 - * - * @access private - * @return void - */ - 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_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() and delete() functions - * - * @access private - * @return void - */ - function _reset_write() - { - $ar_reset_items = array( - 'ar_set' => array(), - 'ar_from' => array(), - 'ar_where' => array(), - 'ar_like' => array(), - 'ar_orderby' => array(), - 'ar_limit' => FALSE, - 'ar_order' => FALSE - ); - - $this->_reset_run($ar_reset_items); - } - -} - -/* End of file DB_active_rec.php */ +_protect_identifiers = $escape; + } + + if (is_string($select)) + { + $select = explode(',', $select); + } + + foreach ($select as $val) + { + $val = trim($val); + + if ($val != '') + { + $this->ar_select[] = $val; + + if ($this->ar_caching === TRUE) + { + $this->ar_cache_select[] = $val; + $this->ar_cache_exists[] = 'select'; + } + } + } + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Select Max + * + * Generates a SELECT MAX(field) portion of a query + * + * @access public + * @param string the field + * @param string an alias + * @return object + */ + 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 + * + * @access public + * @param string the field + * @param string an alias + * @return object + */ + 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 + * + * @access public + * @param string the field + * @param string an alias + * @return object + */ + 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 + * + * @access public + * @param string the field + * @param string an alias + * @return object + */ + 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() + * + * @access public + * @param string the field + * @param string an alias + * @return object + */ + 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 + * + * @access private + * @param string + * @return string + */ + 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 + * + * @access public + * @param bool + * @return object + */ + function distinct($val = TRUE) + { + $this->ar_distinct = (is_bool($val)) ? $val : TRUE; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * From + * + * Generates the FROM portion of the query + * + * @access public + * @param mixed can be a string or array + * @return object + */ + 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 + * + * @access public + * @param string + * @param string the join condition + * @param string the type of join + * @return object + */ + 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 + * + * @access public + * @param mixed + * @param mixed + * @return object + */ + 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 + * + * @access public + * @param mixed + * @param mixed + * @return object + */ + function or_where($key, $value = NULL, $escape = TRUE) + { + return $this->_where($key, $value, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * orwhere() is an alias of or_where() + * this function is here for backwards compatibility, as + * orwhere() has been deprecated + */ + function orwhere($key, $value = NULL, $escape = TRUE) + { + return $this->or_where($key, $value, $escape); + } + + // -------------------------------------------------------------------- + + /** + * Where + * + * Called by where() or orwhere() + * + * @access private + * @param mixed + * @param mixed + * @param string + * @return object + */ + 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 + * + * @access public + * @param string The field to search + * @param array The values searched on + * @return object + */ + 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 + * + * @access public + * @param string The field to search + * @param array The values searched on + * @return object + */ + 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 + * + * @access public + * @param string The field to search + * @param array The values searched on + * @return object + */ + 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 + * + * @access public + * @param string The field to search + * @param array The values searched on + * @return object + */ + 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 + * + * @access public + * @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 + */ + 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 + * + * @access public + * @param mixed + * @param mixed + * @return object + */ + 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 + * + * @access public + * @param mixed + * @param mixed + * @return object + */ + 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 + * + * @access public + * @param mixed + * @param mixed + * @return object + */ + 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 + * + * @access public + * @param mixed + * @param mixed + * @return object + */ + function or_not_like($field, $match = '', $side = 'both') + { + return $this->_like($field, $match, 'OR ', $side, 'NOT'); + } + + // -------------------------------------------------------------------- + + /** + * orlike() is an alias of or_like() + * this function is here for backwards compatibility, as + * orlike() has been deprecated + */ + function orlike($field, $match = '', $side = 'both') + { + return $this->or_like($field, $match, $side); + } + + // -------------------------------------------------------------------- + + /** + * Like + * + * Called by like() or orlike() + * + * @access private + * @param mixed + * @param mixed + * @param string + * @return object + */ + 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 == '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_char); + } + + $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 + * + * @access public + * @param string + * @return object + */ + 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; + } + + // -------------------------------------------------------------------- + + /** + * groupby() is an alias of group_by() + * this function is here for backwards compatibility, as + * groupby() has been deprecated + */ + function groupby($by) + { + return $this->group_by($by); + } + + // -------------------------------------------------------------------- + + /** + * Sets the HAVING value + * + * Separates multiple calls with AND + * + * @access public + * @param string + * @param string + * @return object + */ + function having($key, $value = '', $escape = TRUE) + { + return $this->_having($key, $value, 'AND ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * orhaving() is an alias of or_having() + * this function is here for backwards compatibility, as + * orhaving() has been deprecated + */ + + function orhaving($key, $value = '', $escape = TRUE) + { + return $this->or_having($key, $value, $escape); + } + // -------------------------------------------------------------------- + + /** + * Sets the OR HAVING value + * + * Separates multiple calls with OR + * + * @access public + * @param string + * @param string + * @return object + */ + function or_having($key, $value = '', $escape = TRUE) + { + return $this->_having($key, $value, 'OR ', $escape); + } + + // -------------------------------------------------------------------- + + /** + * Sets the HAVING values + * + * Called by having() or or_having() + * + * @access private + * @param string + * @param string + * @return object + */ + 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_str($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 + * + * @access public + * @param string + * @param string direction: asc or desc + * @return object + */ + 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; + } + + // -------------------------------------------------------------------- + + /** + * orderby() is an alias of order_by() + * this function is here for backwards compatibility, as + * orderby() has been deprecated + */ + function orderby($orderby, $direction = '') + { + return $this->order_by($orderby, $direction); + } + + // -------------------------------------------------------------------- + + /** + * Sets the LIMIT value + * + * @access public + * @param integer the limit value + * @param integer the offset value + * @return object + */ + function limit($value, $offset = '') + { + $this->ar_limit = $value; + + if ($offset != '') + { + $this->ar_offset = $offset; + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Sets the OFFSET value + * + * @access public + * @param integer the offset value + * @return object + */ + function offset($offset) + { + $this->ar_offset = $offset; + return $this; + } + + // -------------------------------------------------------------------- + + /** + * The "set" function. Allows key/value pairs to be set for inserting or updating + * + * @access public + * @param mixed + * @param string + * @param boolean + * @return object + */ + 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)] = $this->escape($v); + } + } + + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Get + * + * Compiles the select statement based on the other functions called + * and runs the query + * + * @access public + * @param string the table + * @param string the limit clause + * @param string the offset clause + * @return object + */ + 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. + * + * @access public + * @param string + * @return string + */ + 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 $row->numrows; + } + + // -------------------------------------------------------------------- + + /** + * Get_Where + * + * Allows the where clause, limit and offset to be added directly + * + * @access public + * @param string the where clause + * @param string the limit clause + * @param string the offset clause + * @return object + */ + 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; + } + + // -------------------------------------------------------------------- + + /** + * getwhere() is an alias of get_where() + * this function is here for backwards compatibility, as + * getwhere() has been deprecated + */ + function getwhere($table = '', $where = null, $limit = null, $offset = null) + { + return $this->get_where($table, $where, $limit, $offset); + } + + // -------------------------------------------------------------------- + + /** + * Insert + * + * Compiles an insert string and runs the query + * + * @access public + * @param string the table to retrieve the results from + * @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); + } + + // -------------------------------------------------------------------- + + /** + * Update + * + * Compiles an update string and runs the query + * + * @access public + * @param string the table to retrieve the results from + * @param array an associative array of update values + * @param mixed the where clause + * @return object + */ + 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); + } + + // -------------------------------------------------------------------- + + /** + * Empty Table + * + * Compiles a delete string and runs "DELETE FROM table" + * + * @access public + * @param string the table to empty + * @return object + */ + 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" + * + * @access public + * @param string the table to truncate + * @return object + */ + 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 + * + * @access public + * @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 + */ + 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 + * + * @access public + * @param string the table + * @return string + */ + function dbprefix($table = '') + { + if ($table == '') + { + $this->display_error('db_table_name_required'); + } + + return $this->dbprefix.$table; + } + + // -------------------------------------------------------------------- + + /** + * Track Aliases + * + * Used to track SQL statements written with aliased tables. + * + * @access private + * @param string The table to inspect + * @return string + */ + 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('/ AS /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. + * + * @access private + * @return string + */ + 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) + { + $this->ar_select[$key] = $this->_protect_identifiers($val); + } + + $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 .= "\n"; + + $sql .= "WHERE "; + } + + $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 + * + * @access public + * @param object + * @return array + */ + 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' && $key != '_ci_scaffolding' && $key != '_ci_scaff_table') + { + $array[$key] = $val; + } + } + + return $array; + } + + // -------------------------------------------------------------------- + + /** + * Start Cache + * + * Starts AR caching + * + * @access public + * @return void + */ + function start_cache() + { + $this->ar_caching = TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Stop Cache + * + * Stops AR caching + * + * @access public + * @return void + */ + function stop_cache() + { + $this->ar_caching = FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Flush Cache + * + * Empties the AR cache + * + * @access public + * @return void + */ + 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() + ) + ); + } + + // -------------------------------------------------------------------- + + /** + * Merge Cache + * + * When called, this function merges any cached AR arrays with + * locally called ones. + * + * @access private + * @return void + */ + 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); + } + } + + // -------------------------------------------------------------------- + + /** + * Resets the active record values. Called by the get() function + * + * @access private + * @param array An array of fields to reset + * @return void + */ + 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 + * + * @access private + * @return void + */ + 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_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() and delete() functions + * + * @access private + * @return void + */ + function _reset_write() + { + $ar_reset_items = array( + 'ar_set' => array(), + 'ar_from' => array(), + 'ar_where' => array(), + 'ar_like' => array(), + 'ar_orderby' => 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 index 5ba6197..3121a04 100644 --- a/system/database/DB_cache.php +++ b/system/database/DB_cache.php @@ -1,195 +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, DIR_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 */ +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, DIR_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 index 607853d..30d70f1 100644 --- a/system/database/DB_driver.php +++ b/system/database/DB_driver.php @@ -1,1366 +1,1366 @@ - $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; - } - - if ($this->dbdriver == 'oci8') - { - return $sql; - } - - $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); - } - - // 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; - } - } - } - - // Compile binds if needed - if ($binds !== FALSE) - { - $sql = $this->compile_binds($sql, $binds); - } - - // 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'.EXT); - include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT); - } - - 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($this->_protect_identifiers($table, TRUE, NULL, FALSE)))) - { - 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; - - 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'.EXT)) - { - 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('Language'); - $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; - } - - $error =& load_class('Exceptions'); - 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 - $alias = ''; - if (strpos($item, ' ') !== FALSE) - { - $alias = strstr($item, " "); - $item = substr($item, 0, - strlen($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; - } - - -} - - -/* End of file DB_driver.php */ + $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; + } + + if ($this->dbdriver == 'oci8') + { + return $sql; + } + + $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); + } + + // 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; + } + } + } + + // Compile binds if needed + if ($binds !== FALSE) + { + $sql = $this->compile_binds($sql, $binds); + } + + // 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'.EXT); + include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result'.EXT); + } + + 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($this->_protect_identifiers($table, TRUE, NULL, FALSE)))) + { + 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; + + 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'.EXT)) + { + 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('Language'); + $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; + } + + $error =& load_class('Exceptions'); + 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 + $alias = ''; + if (strpos($item, ' ') !== FALSE) + { + $alias = strstr($item, " "); + $item = substr($item, 0, - strlen($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; + } + + +} + + +/* 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 index c1cd64d..fd482c4 100644 --- a/system/database/DB_forge.php +++ b/system/database/DB_forge.php @@ -1,375 +1,375 @@ -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($table_name, $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) - { - $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 */ +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($table_name, $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) + { + $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 index 70dd1cd..f9f33f1 100644 --- a/system/database/DB_result.php +++ b/system/database/DB_result.php @@ -1,342 +1,342 @@ -result_object() : $this->result_array(); - } - - // -------------------------------------------------------------------- - - /** - * Query result. "object" version. - * - * @access public - * @return object - */ - 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 - */ - 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 - */ - 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; - } - - return ($type == 'object') ? $this->row_object($n) : $this->row_array($n); - } - - // -------------------------------------------------------------------- - - /** - * Assigns an item into a particular column slot - * - * @access public - * @return object - */ - 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 - object version - * - * @access public - * @return object - */ - 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 - */ - 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 - */ - 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 - */ - 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 - */ - 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 - */ - 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. - */ - function num_rows() { return $this->num_rows; } - function num_fields() { return 0; } - function list_fields() { return array(); } - function field_data() { return array(); } - function free_result() { return TRUE; } - function _data_seek() { return TRUE; } - function _fetch_assoc() { return array(); } - function _fetch_object() { return array(); } - -} -// END DB_result class - -/* End of file DB_result.php */ +result_object() : $this->result_array(); + } + + // -------------------------------------------------------------------- + + /** + * Query result. "object" version. + * + * @access public + * @return object + */ + 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 + */ + 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 + */ + 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; + } + + return ($type == 'object') ? $this->row_object($n) : $this->row_array($n); + } + + // -------------------------------------------------------------------- + + /** + * Assigns an item into a particular column slot + * + * @access public + * @return object + */ + 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 - object version + * + * @access public + * @return object + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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. + */ + function num_rows() { return $this->num_rows; } + function num_fields() { return 0; } + function list_fields() { return array(); } + function field_data() { return array(); } + function free_result() { return TRUE; } + function _data_seek() { return TRUE; } + function _fetch_assoc() { return array(); } + function _fetch_object() { return array(); } + +} +// END DB_result class + +/* End of file DB_result.php */ /* Location: ./system/database/DB_result.php */ \ No newline at end of file diff --git a/system/database/DB_utility.php b/system/database/DB_utility.php index abab741..6de844f 100644 --- a/system/database/DB_utility.php +++ b/system/database/DB_utility.php @@ -1,389 +1,389 @@ -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']; - } - - // -------------------------------------------------------------------- - - /** - * 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 */ +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']; + } + + // -------------------------------------------------------------------- + + /** + * 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/index.html b/system/database/drivers/index.html index c942a79..065d2da 100644 --- a/system/database/drivers/index.html +++ b/system/database/drivers/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index c942a79..065d2da 100644 --- a/system/database/drivers/mssql/index.html +++ b/system/database/drivers/mssql/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index 412dabc..fd0c188 100644 --- a/system/database/drivers/mssql/mssql_driver.php +++ b/system/database/drivers/mssql/mssql_driver.php @@ -1,667 +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; - } - - // Access the CI object - $CI =& get_instance(); - - // Escape single quotes - $str = str_replace("'", "''", $CI->input->_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(); - 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_char); - 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 */ +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; + } + + // Access the CI object + $CI =& get_instance(); + + // Escape single quotes + $str = str_replace("'", "''", $CI->input->_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(); + 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_char); + 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 index 5aa4406..e22d3e7 100644 --- a/system/database/drivers/mssql/mssql_forge.php +++ b/system/database/drivers/mssql/mssql_forge.php @@ -1,248 +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 */ +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 index b6d5328..4fde784 100644 --- a/system/database/drivers/mssql/mssql_result.php +++ b/system/database/drivers/mssql/mssql_result.php @@ -1,169 +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 */ +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 index 224fcbc..576c07a 100644 --- a/system/database/drivers/mssql/mssql_utility.php +++ b/system/database/drivers/mssql/mssql_utility.php @@ -1,123 +1,123 @@ -db->display_error('db_unsuported_feature'); - } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - -} - - -/* End of file mssql_utility.php */ +db->display_error('db_unsuported_feature'); + } + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access private + * @param string the database name + * @return bool + */ + function _create_database($name) + { + return "CREATE DATABASE ".$name; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + return "DROP DATABASE ".$name; + } + +} + + +/* 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 index c942a79..065d2da 100644 --- a/system/database/drivers/mysql/index.html +++ b/system/database/drivers/mysql/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index 04a97c4..f33b1dd 100644 --- a/system/database/drivers/mysql/mysql_driver.php +++ b/system/database/drivers/mysql/mysql_driver.php @@ -1,670 +1,670 @@ -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) - { - return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $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(); - 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 ".$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 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).")"; - } - - // -------------------------------------------------------------------- - - /** - * 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) - { - 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 */ +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) + { + return @mysql_query("SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'", $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(); + 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 ".$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 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).")"; + } + + // -------------------------------------------------------------------- + + /** + * 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) + { + 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 index 973f32d..9c6c7ff 100644 --- a/system/database/drivers/mysql/mysql_forge.php +++ b/system/database/drivers/mysql/mysql_forge.php @@ -1,254 +1,254 @@ -$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)) - { - $sql .= ($attributes['NULL'] === TRUE) ? ' NULL' : ' 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 */ +$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)) + { + $sql .= ($attributes['NULL'] === TRUE) ? ' NULL' : ' 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 index 88452a2..b5dc5e4 100644 --- a/system/database/drivers/mysql/mysql_result.php +++ b/system/database/drivers/mysql/mysql_result.php @@ -1,169 +1,169 @@ -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_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; - $F->primary_key = $field->primary_key; - - $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 */ +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_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; + $F->primary_key = $field->primary_key; + + $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 index ea19220..a78fd07 100644 --- a/system/database/drivers/mysql/mysql_utility.php +++ b/system/database/drivers/mysql/mysql_utility.php @@ -1,245 +1,245 @@ -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; - } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - -} - -/* End of file mysql_utility.php */ +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; + } + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access private + * @param string the database name + * @return bool + */ + function _create_database($name) + { + return "CREATE DATABASE ".$name; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + return "DROP DATABASE ".$name; + } + +} + +/* 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 index c942a79..065d2da 100644 --- a/system/database/drivers/mysqli/index.html +++ b/system/database/drivers/mysqli/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index cca1334..0a62858 100644 --- a/system/database/drivers/mysqli/mysqli_driver.php +++ b/system/database/drivers/mysqli/mysqli_driver.php @@ -1,671 +1,671 @@ -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) - { - return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'"); - } - - // -------------------------------------------------------------------- - - /** - * 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(); - 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 ".$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 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).")"; - } - - // -------------------------------------------------------------------- - - /** - * 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) - { - @mysqli_close($conn_id); - } - - -} - - -/* End of file mysqli_driver.php */ +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) + { + return @mysqli_query($this->conn_id, "SET NAMES '".$this->escape_str($charset)."' COLLATE '".$this->escape_str($collation)."'"); + } + + // -------------------------------------------------------------------- + + /** + * 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(); + 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 ".$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 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).")"; + } + + // -------------------------------------------------------------------- + + /** + * 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) + { + @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 index 85491a8..9a87fd6 100644 --- a/system/database/drivers/mysqli/mysqli_forge.php +++ b/system/database/drivers/mysqli/mysqli_forge.php @@ -1,254 +1,254 @@ -$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)) - { - $sql .= ($attributes['NULL'] === TRUE) ? ' NULL' : ' 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 */ +$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)) + { + $sql .= ($attributes['NULL'] === TRUE) ? ' NULL' : ' 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 index 79e8a58..6f30306 100644 --- a/system/database/drivers/mysqli/mysqli_result.php +++ b/system/database/drivers/mysqli/mysqli_result.php @@ -1,169 +1,169 @@ -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_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; - $F->primary_key = ($field->flags & MYSQLI_PRI_KEY_FLAG) ? 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 */ +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_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; + $F->primary_key = ($field->flags & MYSQLI_PRI_KEY_FLAG) ? 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 index 99a8064..797a808 100644 --- a/system/database/drivers/mysqli/mysqli_utility.php +++ b/system/database/drivers/mysqli/mysqli_utility.php @@ -1,123 +1,123 @@ -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'); - } - - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - -} - -/* End of file mysqli_utility.php */ +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'); + } + + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access private + * @param string the database name + * @return bool + */ + function _create_database($name) + { + return "CREATE DATABASE ".$name; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + return "DROP DATABASE ".$name; + } + +} + +/* 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 index c942a79..065d2da 100644 --- a/system/database/drivers/oci8/index.html +++ b/system/database/drivers/oci8/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index 6ef2899..0424283 100644 --- a/system/database/drivers/oci8/oci8_driver.php +++ b/system/database/drivers/oci8/oci8_driver.php @@ -1,780 +1,780 @@ -username, $this->password, $this->hostname); - } - - // -------------------------------------------------------------------- - - /** - * Persistent database connection - * - * @access private called by the base class - * @return resource - */ - function db_pconnect() - { - return @ociplogon($this->username, $this->password, $this->hostname); - } - - // -------------------------------------------------------------------- - - /** - * 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 oracle - } - - // -------------------------------------------------------------------- - - /** - * 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 ociserverversion($this->conn_id); - } - - // -------------------------------------------------------------------- - - /** - * Execute the query - * - * @access private called by the base class - * @param string an SQL query - * @return resource - */ - 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); - ocisetprefetch($this->stmt_id, 1000); - return @ociexecute($this->stmt_id, $this->_commit); - } - - /** - * Generate a statement ID - * - * @access private - * @param string an SQL query - * @return none - */ - function _set_stmt_id($sql) - { - if ( ! is_resource($this->stmt_id)) - { - $this->stmt_id = ociparse($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 - */ - function _prep_query($sql) - { - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * getCursor. Returns a cursor from the datbase - * - * @access public - * @return cursor id - */ - function get_cursor() - { - $this->curs_id = ocinewcursor($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 - */ - 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 - */ - 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] = ''; - } - } - - ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']); - } - } - - // -------------------------------------------------------------------- - - /** - * 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->_commit = OCI_DEFAULT; - 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; - } - - $ret = OCIcommit($this->conn_id); - $this->_commit = OCI_COMMIT_ON_SUCCESS; - 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 = OCIrollback($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 - */ - function escape_str($str, $like = FALSE) - { - if (is_array($str)) - { - foreach($str as $key => $val) - { - $str[$key] = $this->escape_str($val, $like); - } - - return $str; - } - - // Access the CI object - $CI =& get_instance(); - - $str = $CI->input->_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 @ocirowcount($this->stmt_id); - } - - // -------------------------------------------------------------------- - - /** - * Insert ID - * - * @access public - * @return integer - */ - 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 - */ - 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(); - 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 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_char); - } - - 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 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 - */ - function _field_data($table) - { - return "SELECT * FROM ".$table." where rownum = 1"; - } - - // -------------------------------------------------------------------- - - /** - * The error message string - * - * @access private - * @return string - */ - function _error_message() - { - $error = ocierror($this->conn_id); - return $error['message']; - } - - // -------------------------------------------------------------------- - - /** - * The error message number - * - * @access private - * @return integer - */ - function _error_number() - { - $error = ocierror($this->conn_id); - return $error['code']; - } - - // -------------------------------------------------------------------- - - /** - * 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 ".$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) - { - $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 public - * @param resource - * @return void - */ - function _close($conn_id) - { - @ocilogoff($conn_id); - } - - -} - - - -/* End of file oci8_driver.php */ +username, $this->password, $this->hostname); + } + + // -------------------------------------------------------------------- + + /** + * Persistent database connection + * + * @access private called by the base class + * @return resource + */ + function db_pconnect() + { + return @ociplogon($this->username, $this->password, $this->hostname); + } + + // -------------------------------------------------------------------- + + /** + * 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 oracle + } + + // -------------------------------------------------------------------- + + /** + * 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 ociserverversion($this->conn_id); + } + + // -------------------------------------------------------------------- + + /** + * Execute the query + * + * @access private called by the base class + * @param string an SQL query + * @return resource + */ + 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); + ocisetprefetch($this->stmt_id, 1000); + return @ociexecute($this->stmt_id, $this->_commit); + } + + /** + * Generate a statement ID + * + * @access private + * @param string an SQL query + * @return none + */ + function _set_stmt_id($sql) + { + if ( ! is_resource($this->stmt_id)) + { + $this->stmt_id = ociparse($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 + */ + function _prep_query($sql) + { + return $sql; + } + + // -------------------------------------------------------------------- + + /** + * getCursor. Returns a cursor from the datbase + * + * @access public + * @return cursor id + */ + function get_cursor() + { + $this->curs_id = ocinewcursor($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 + */ + 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 + */ + 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] = ''; + } + } + + ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']); + } + } + + // -------------------------------------------------------------------- + + /** + * 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->_commit = OCI_DEFAULT; + 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; + } + + $ret = OCIcommit($this->conn_id); + $this->_commit = OCI_COMMIT_ON_SUCCESS; + 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 = OCIrollback($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 + */ + function escape_str($str, $like = FALSE) + { + if (is_array($str)) + { + foreach($str as $key => $val) + { + $str[$key] = $this->escape_str($val, $like); + } + + return $str; + } + + // Access the CI object + $CI =& get_instance(); + + $str = $CI->input->_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 @ocirowcount($this->stmt_id); + } + + // -------------------------------------------------------------------- + + /** + * Insert ID + * + * @access public + * @return integer + */ + 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 + */ + 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(); + 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 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_char); + } + + 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 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 + */ + function _field_data($table) + { + return "SELECT * FROM ".$table." where rownum = 1"; + } + + // -------------------------------------------------------------------- + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + $error = ocierror($this->conn_id); + return $error['message']; + } + + // -------------------------------------------------------------------- + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + $error = ocierror($this->conn_id); + return $error['code']; + } + + // -------------------------------------------------------------------- + + /** + * 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 ".$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) + { + $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 public + * @param resource + * @return void + */ + function _close($conn_id) + { + @ocilogoff($conn_id); + } + + +} + + + +/* End of file oci8_driver.php */ /* Location: ./system/database/drivers/oci8/oci8_driver.php */ \ No newline at end of file diff --git a/system/database/drivers/oci8/oci8_forge.php b/system/database/drivers/oci8/oci8_forge.php index 1d369ae..5552f23 100644 --- a/system/database/drivers/oci8/oci8_forge.php +++ b/system/database/drivers/oci8/oci8_forge.php @@ -1,248 +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 */ +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 index c241150..0e87329 100644 --- a/system/database/drivers/oci8/oci8_result.php +++ b/system/database/drivers/oci8/oci8_result.php @@ -1,249 +1,249 @@ -result_array()); - @ociexecute($this->stmt_id); - - if ($this->curs_id) - { - @ociexecute($this->curs_id); - } - - return $rowcount; - } - - // -------------------------------------------------------------------- - - /** - * Number of fields in the result set - * - * @access public - * @return integer - */ - function num_fields() - { - $count = @ocinumcols($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 - */ - function list_fields() - { - $field_names = array(); - $fieldCount = $this->num_fields(); - for ($c = 1; $c <= $fieldCount; $c++) - { - $field_names[] = ocicolumnname($this->stmt_id, $c); - } - return $field_names; - } - - // -------------------------------------------------------------------- - - /** - * Field data - * - * Generates an array of objects containing field meta-data - * - * @access public - * @return array - */ - function field_data() - { - $retval = array(); - $fieldCount = $this->num_fields(); - for ($c = 1; $c <= $fieldCount; $c++) - { - $F = new stdClass(); - $F->name = ocicolumnname($this->stmt_id, $c); - $F->type = ocicolumntype($this->stmt_id, $c); - $F->max_length = ocicolumnsize($this->stmt_id, $c); - - $retval[] = $F; - } - - return $retval; - } - - // -------------------------------------------------------------------- - - /** - * Free the result - * - * @return null - */ - function free_result() - { - if (is_resource($this->result_id)) - { - ocifreestatement($this->result_id); - $this->result_id = FALSE; - } - } - - // -------------------------------------------------------------------- - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @access private - * @return array - */ - function _fetch_assoc(&$row) - { - $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; - - return ocifetchinto($id, $row, OCI_ASSOC + OCI_RETURN_NULLS); - } - - // -------------------------------------------------------------------- - - /** - * Result - object - * - * Returns the result set as an object - * - * @access private - * @return object - */ - function _fetch_object() - { - $result = array(); - - // If PHP 5 is being used we can fetch an result object - if (function_exists('oci_fetch_object')) - { - $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; - - return @oci_fetch_object($id); - } - - // If PHP 4 is being used we have to build our own result - foreach ($this->result_array() as $key => $val) - { - $obj = new stdClass(); - if (is_array($val)) - { - foreach ($val as $k => $v) - { - $obj->$k = $v; - } - } - else - { - $obj->$key = $val; - } - - $result[] = $obj; - } - - return $result; - } - - // -------------------------------------------------------------------- - - /** - * Query result. "array" version. - * - * @access public - * @return array - */ - function result_array() - { - if (count($this->result_array) > 0) - { - return $this->result_array; - } - - // oracle's fetch functions do not return arrays. - // The information is returned in reference parameters - $row = NULL; - while ($this->_fetch_assoc($row)) - { - $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 private - * @return array - */ - function _data_seek($n = 0) - { - return FALSE; // Not needed - } - -} - - -/* End of file oci8_result.php */ +result_array()); + @ociexecute($this->stmt_id); + + if ($this->curs_id) + { + @ociexecute($this->curs_id); + } + + return $rowcount; + } + + // -------------------------------------------------------------------- + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + $count = @ocinumcols($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 + */ + function list_fields() + { + $field_names = array(); + $fieldCount = $this->num_fields(); + for ($c = 1; $c <= $fieldCount; $c++) + { + $field_names[] = ocicolumnname($this->stmt_id, $c); + } + return $field_names; + } + + // -------------------------------------------------------------------- + + /** + * Field data + * + * Generates an array of objects containing field meta-data + * + * @access public + * @return array + */ + function field_data() + { + $retval = array(); + $fieldCount = $this->num_fields(); + for ($c = 1; $c <= $fieldCount; $c++) + { + $F = new stdClass(); + $F->name = ocicolumnname($this->stmt_id, $c); + $F->type = ocicolumntype($this->stmt_id, $c); + $F->max_length = ocicolumnsize($this->stmt_id, $c); + + $retval[] = $F; + } + + return $retval; + } + + // -------------------------------------------------------------------- + + /** + * Free the result + * + * @return null + */ + function free_result() + { + if (is_resource($this->result_id)) + { + ocifreestatement($this->result_id); + $this->result_id = FALSE; + } + } + + // -------------------------------------------------------------------- + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc(&$row) + { + $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; + + return ocifetchinto($id, $row, OCI_ASSOC + OCI_RETURN_NULLS); + } + + // -------------------------------------------------------------------- + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + $result = array(); + + // If PHP 5 is being used we can fetch an result object + if (function_exists('oci_fetch_object')) + { + $id = ($this->curs_id) ? $this->curs_id : $this->stmt_id; + + return @oci_fetch_object($id); + } + + // If PHP 4 is being used we have to build our own result + foreach ($this->result_array() as $key => $val) + { + $obj = new stdClass(); + if (is_array($val)) + { + foreach ($val as $k => $v) + { + $obj->$k = $v; + } + } + else + { + $obj->$key = $val; + } + + $result[] = $obj; + } + + return $result; + } + + // -------------------------------------------------------------------- + + /** + * Query result. "array" version. + * + * @access public + * @return array + */ + function result_array() + { + if (count($this->result_array) > 0) + { + return $this->result_array; + } + + // oracle's fetch functions do not return arrays. + // The information is returned in reference parameters + $row = NULL; + while ($this->_fetch_assoc($row)) + { + $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 private + * @return array + */ + function _data_seek($n = 0) + { + return FALSE; // Not needed + } + +} + + +/* End of file oci8_result.php */ /* Location: ./system/database/drivers/oci8/oci8_result.php */ \ No newline at end of file diff --git a/system/database/drivers/oci8/oci8_utility.php b/system/database/drivers/oci8/oci8_utility.php index 74670ea..24d1fbb 100644 --- a/system/database/drivers/oci8/oci8_utility.php +++ b/system/database/drivers/oci8/oci8_utility.php @@ -1,122 +1,122 @@ -db->display_error('db_unsuported_feature'); - } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access public - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return FALSE; - } - -} - -/* End of file oci8_utility.php */ +db->display_error('db_unsuported_feature'); + } + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access public + * @param string the database name + * @return bool + */ + function _create_database($name) + { + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + return FALSE; + } + +} + +/* 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 index c942a79..065d2da 100644 --- a/system/database/drivers/odbc/index.html +++ b/system/database/drivers/odbc/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index c3717c1..170a573 100644 --- a/system/database/drivers/odbc/odbc_driver.php +++ b/system/database/drivers/odbc/odbc_driver.php @@ -1,639 +1,639 @@ -_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; - } - - // Access the CI object - $CI =& get_instance(); - - // ODBC doesn't require escaping - $str = $CI->input->_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(); - 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_char); - 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 */ +_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; + } + + // Access the CI object + $CI =& get_instance(); + + // ODBC doesn't require escaping + $str = $CI->input->_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(); + 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_char); + 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 index 49a2401..228612e 100644 --- a/system/database/drivers/odbc/odbc_forge.php +++ b/system/database/drivers/odbc/odbc_forge.php @@ -1,266 +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 */ +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 index 20b696b..05e1b15 100644 --- a/system/database/drivers/odbc/odbc_result.php +++ b/system/database/drivers/odbc/odbc_result.php @@ -1,228 +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 */ +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 index 2e8ff93..a1a6b2b 100644 --- a/system/database/drivers/odbc/odbc_utility.php +++ b/system/database/drivers/odbc/odbc_utility.php @@ -1,148 +1,148 @@ -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'); - } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database() - { - // ODBC has no "create 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; - } - - // -------------------------------------------------------------------- - - /** - * 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; - } -} - -/* End of file odbc_utility.php */ +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'); + } + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access private + * @param string the database name + * @return bool + */ + function _create_database() + { + // ODBC has no "create 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; + } + + // -------------------------------------------------------------------- + + /** + * 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; + } +} + +/* 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/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php index a44c48e..084eadb 100644 --- a/system/database/drivers/pdo/pdo_driver.php +++ b/system/database/drivers/pdo/pdo_driver.php @@ -1,610 +1,610 @@ -database, $this->username, $this->password); - log_message('debug', 'connecting ' . $this->database); - } - catch (PDOException $e) - { - log_message('error', $e->getMessage()); - - if ($this->db_debug) - { - $this->display_error($e->getMessage(), '', TRUE); - } - } - - log_message('debug', print_r($conn_id, true)); - - if ($conn_id) - { - log_message('debug', 'connection ok'); - } - - return $conn_id; - } - - /** - * Persistent database connection - * - * @access private, called by the base class - * @return resource - */ - function db_pconnect() - { - try - { - $conn_id = new PDO ($this->database, $this->username, $this->password, array(PDO::ATTR_PERSISTENT => true)); - } - catch (PDOException $e) - { - log_message('error', $e->getMessage()); - - if ($this->db_debug) - { - $this->display_error($e->getMessage(), '', TRUE); - } - } - - return $conn_id; - } - - /** - * Select the database - * - * @access private called by the base class - * @return resource - */ - function db_select() - { - 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); - log_message('debug', 'SQL : ' . $sql); - - return @$this->conn_id->query($sql); // Do we really need to use error supression here? :( - } - - /** - * 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; - } - - /** - * "Smart" Escape String - * - * Escapes data based on type - * Sets boolean and null types - * - * @access public - * @param string - * @return integer - */ - function escape($str) - { - switch (gettype($str)) - { - case 'string': - $str = $this->escape_str($str); - break; - case 'boolean': - $str = ($str === FALSE) ? 0 : 1; - break; - default: - $str = ($str === NULL) ? 'NULL' : $str; - break; - } - - return $str; - } - - /** - * Escape String - * - * @access public - * @param string - * @return string - */ - function escape_str($str) - { - if (get_magic_quotes_gpc()) - { - $str = stripslashes($str); - } - - return $this->conn_id->quote($str); - } - - /** - * Close DB Connection - * - * @access public - * @param resource - * @return void - */ - function destroy($conn_id) - { - $conn_id = null; - } - - /** - * Insert ID - * - * @access public - * @return integer - */ - function insert_id() - { - return @$this->conn_id->lastInsertId(); - } - - /** - * "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 `' . $table . '`'); - - if ($query->num_rows() == 0) - { - return '0'; - } - - $row = $query->row(); - - return $row->numrows; - } - - /** - * The error message string - * - * @access private - * @return string - */ - function _error_message() - { - $infos = $this->conn_id->errorInfo(); - - return $infos[2]; - } - - /** - * The error message number - * - * @access private - * @return integer - */ - function _error_number() - { - $infos = $this->conn_id->errorInfo(); - - return $infos[1]; - } - - /** - * Version number query string - * - * @access public - * @return string - */ - function version() - { - return $this->conn_id->getAttribute(constant("PDO::ATTR_SERVER_VERSION")); - } - - /** - * 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 public - * @param string the table name - * @return string - */ - function escape_table($table) - { - if (stristr($table, '.')) - { - $table = preg_replace("/\./", '`.`', $table); - } - - return $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) - { - $sql = 'SELECT * FROM ' . $this->escape_table($table) . ' LIMIT 1'; - $query = $this->query($sql); - - return $query->field_data(); - } - - /** - * 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 - * @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); - } - - /** - * Delete statement - * - * Generates a platform-specific delete string from the supplied data - * - * @access public - * @param string the table name - * @param array the where clause - * @return string - */ - function _delete($table, $where) - { - return "DELETE FROM " . $this->escape_table($table) . " WHERE " . implode(" ", $where); - } - - /** - * Show table query - * - * Generates a platform-specific query string so that the table names can be fetched - * - * @access public - * @return string - */ - function _show_tables() - { - return "SELECT name from sqlite_master WHERE type='table'"; - } - - /** - * Show columnn 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 _show_columns($table = '') - { - // Not supported - return FALSE; - } - - /** - * 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; - } - - - - // ----------------------------------------------------------------- - /** - * 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; - } - - // -------------------------------------------------------------------- - - /** - * Protect Identifiers - * - * This function adds backticks if appropriate based on db type - * - * @access private - * @param mixed the item to escape - * @param boolean only affect the first word - * @return mixed the item with backticks - */ - function _protect_identifiers($item, $first_word_only = FALSE) - { - if (is_array($item)) - { - $escaped_array = array(); - - foreach($item as $k=>$v) - { - $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only); - } - - return $escaped_array; - } - - // This function may get "item1 item2" as a string, and so - // we may need "item1 item2" and not "item1 item2" - if (ctype_alnum($item) === FALSE) - { - if (strpos($item, '.') !== FALSE) - { - $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; - $table_name = substr($item, 0, strpos($item, '.')+1); - $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; - } - - // This function may get "field >= 1", and need it to return "field >= 1" - $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; - - $item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1$2$3', $item); - } - else - { - return "{$item}"; - } - - $exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS'); - - foreach ($exceptions as $exception) - { - - if (stristr($item, " {$exception} ") !== FALSE) - { - $item = preg_replace('/ ('.preg_quote($exception).') /i', ' $1 ', $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).')'; - } - - // -------------------------------------------------------------------- - - /** - * 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; - } - - /** - * 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; - } - - - // -------------------------------------------------------------------- - - /** - * Close DB Connection - * - * @access public - * @param resource - * @return void - */ - function _close($conn_id) - { - return true; - } - - -} - -?> +database, $this->username, $this->password); + log_message('debug', 'connecting ' . $this->database); + } + catch (PDOException $e) + { + log_message('error', $e->getMessage()); + + if ($this->db_debug) + { + $this->display_error($e->getMessage(), '', TRUE); + } + } + + log_message('debug', print_r($conn_id, true)); + + if ($conn_id) + { + log_message('debug', 'connection ok'); + } + + return $conn_id; + } + + /** + * Persistent database connection + * + * @access private, called by the base class + * @return resource + */ + function db_pconnect() + { + try + { + $conn_id = new PDO ($this->database, $this->username, $this->password, array(PDO::ATTR_PERSISTENT => true)); + } + catch (PDOException $e) + { + log_message('error', $e->getMessage()); + + if ($this->db_debug) + { + $this->display_error($e->getMessage(), '', TRUE); + } + } + + return $conn_id; + } + + /** + * Select the database + * + * @access private called by the base class + * @return resource + */ + function db_select() + { + 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); + log_message('debug', 'SQL : ' . $sql); + + return @$this->conn_id->query($sql); // Do we really need to use error supression here? :( + } + + /** + * 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; + } + + /** + * "Smart" Escape String + * + * Escapes data based on type + * Sets boolean and null types + * + * @access public + * @param string + * @return integer + */ + function escape($str) + { + switch (gettype($str)) + { + case 'string': + $str = $this->escape_str($str); + break; + case 'boolean': + $str = ($str === FALSE) ? 0 : 1; + break; + default: + $str = ($str === NULL) ? 'NULL' : $str; + break; + } + + return $str; + } + + /** + * Escape String + * + * @access public + * @param string + * @return string + */ + function escape_str($str) + { + if (get_magic_quotes_gpc()) + { + $str = stripslashes($str); + } + + return $this->conn_id->quote($str); + } + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function destroy($conn_id) + { + $conn_id = null; + } + + /** + * Insert ID + * + * @access public + * @return integer + */ + function insert_id() + { + return @$this->conn_id->lastInsertId(); + } + + /** + * "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 `' . $table . '`'); + + if ($query->num_rows() == 0) + { + return '0'; + } + + $row = $query->row(); + + return $row->numrows; + } + + /** + * The error message string + * + * @access private + * @return string + */ + function _error_message() + { + $infos = $this->conn_id->errorInfo(); + + return $infos[2]; + } + + /** + * The error message number + * + * @access private + * @return integer + */ + function _error_number() + { + $infos = $this->conn_id->errorInfo(); + + return $infos[1]; + } + + /** + * Version number query string + * + * @access public + * @return string + */ + function version() + { + return $this->conn_id->getAttribute(constant("PDO::ATTR_SERVER_VERSION")); + } + + /** + * 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 public + * @param string the table name + * @return string + */ + function escape_table($table) + { + if (stristr($table, '.')) + { + $table = preg_replace("/\./", '`.`', $table); + } + + return $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) + { + $sql = 'SELECT * FROM ' . $this->escape_table($table) . ' LIMIT 1'; + $query = $this->query($sql); + + return $query->field_data(); + } + + /** + * 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 + * @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); + } + + /** + * Delete statement + * + * Generates a platform-specific delete string from the supplied data + * + * @access public + * @param string the table name + * @param array the where clause + * @return string + */ + function _delete($table, $where) + { + return "DELETE FROM " . $this->escape_table($table) . " WHERE " . implode(" ", $where); + } + + /** + * Show table query + * + * Generates a platform-specific query string so that the table names can be fetched + * + * @access public + * @return string + */ + function _show_tables() + { + return "SELECT name from sqlite_master WHERE type='table'"; + } + + /** + * Show columnn 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 _show_columns($table = '') + { + // Not supported + return FALSE; + } + + /** + * 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; + } + + + + // ----------------------------------------------------------------- + /** + * 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; + } + + // -------------------------------------------------------------------- + + /** + * Protect Identifiers + * + * This function adds backticks if appropriate based on db type + * + * @access private + * @param mixed the item to escape + * @param boolean only affect the first word + * @return mixed the item with backticks + */ + function _protect_identifiers($item, $first_word_only = FALSE) + { + if (is_array($item)) + { + $escaped_array = array(); + + foreach($item as $k=>$v) + { + $escaped_array[$this->_protect_identifiers($k)] = $this->_protect_identifiers($v, $first_word_only); + } + + return $escaped_array; + } + + // This function may get "item1 item2" as a string, and so + // we may need "item1 item2" and not "item1 item2" + if (ctype_alnum($item) === FALSE) + { + if (strpos($item, '.') !== FALSE) + { + $aliased_tables = implode(".",$this->ar_aliased_tables).'.'; + $table_name = substr($item, 0, strpos($item, '.')+1); + $item = (strpos($aliased_tables, $table_name) !== FALSE) ? $item = $item : $this->dbprefix.$item; + } + + // This function may get "field >= 1", and need it to return "field >= 1" + $lbound = ($first_word_only === TRUE) ? '' : '|\s|\('; + + $item = preg_replace('/(^'.$lbound.')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1$2$3', $item); + } + else + { + return "{$item}"; + } + + $exceptions = array('AS', '/', '-', '%', '+', '*', 'OR', 'IS'); + + foreach ($exceptions as $exception) + { + + if (stristr($item, " {$exception} ") !== FALSE) + { + $item = preg_replace('/ ('.preg_quote($exception).') /i', ' $1 ', $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).')'; + } + + // -------------------------------------------------------------------- + + /** + * 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; + } + + /** + * 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; + } + + + // -------------------------------------------------------------------- + + /** + * Close DB Connection + * + * @access public + * @param resource + * @return void + */ + function _close($conn_id) + { + return true; + } + + +} + +?> diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php index ffe724e..967e5b7 100644 --- a/system/database/drivers/pdo/pdo_result.php +++ b/system/database/drivers/pdo/pdo_result.php @@ -1,154 +1,154 @@ - numrows - * 2/ select * from table where $where - * => treatment - * - * Holy cow ! - * - * @access public - * @return integer - */ - function num_rows() - { - if (!$this->pdo_results) - { - $this->pdo_results = $this->result_id->fetchAll(PDO::FETCH_ASSOC); - } - - return sizeof($this->pdo_results); - } - - /** - * Number of fields in the result set - * - * @access public - * @return integer - */ - function num_fields() - { - if (is_array($this->pdo_results)) - { - return sizeof($this->pdo_results[$this->pdo_index]); - } - else - { - return $this->result_id->columnCount(); - } - } - - /** - * 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 CI_DB_field(); - $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; - } - */ - - /** - * Result - associative array - * - * Returns the result set as an array - * - * @access private - * @return array - */ - function _fetch_assoc() - { - if (is_array($this->pdo_results)) - { - $i = $this->pdo_index; - $this->pdo_index++; - - if (isset($this->pdo_results[$i])) - { - return $this->pdo_results[$i]; - } - - return null; - } - - return $this->result_id->fetch(PDO::FETCH_ASSOC); - } - - /** - * Result - object - * - * Returns the result set as an object - * - * @access private - * @return object - */ - function _fetch_object() - { - if (is_array($this->pdo_results)) - { - $i = $this->pdo_index; - $this->pdo_index++; - - if (isset($this->pdo_results[$i])) - { - $back = ''; - - foreach ($this->pdo_results[$i] as $key => $val) - { - $back->$key = $val; - } - - return $back; - } - - return null; - } - - return $this->result_id->fetch(PDO::FETCH_OBJ); - } -} + numrows + * 2/ select * from table where $where + * => treatment + * + * Holy cow ! + * + * @access public + * @return integer + */ + function num_rows() + { + if (!$this->pdo_results) + { + $this->pdo_results = $this->result_id->fetchAll(PDO::FETCH_ASSOC); + } + + return sizeof($this->pdo_results); + } + + /** + * Number of fields in the result set + * + * @access public + * @return integer + */ + function num_fields() + { + if (is_array($this->pdo_results)) + { + return sizeof($this->pdo_results[$this->pdo_index]); + } + else + { + return $this->result_id->columnCount(); + } + } + + /** + * 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 CI_DB_field(); + $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; + } + */ + + /** + * Result - associative array + * + * Returns the result set as an array + * + * @access private + * @return array + */ + function _fetch_assoc() + { + if (is_array($this->pdo_results)) + { + $i = $this->pdo_index; + $this->pdo_index++; + + if (isset($this->pdo_results[$i])) + { + return $this->pdo_results[$i]; + } + + return null; + } + + return $this->result_id->fetch(PDO::FETCH_ASSOC); + } + + /** + * Result - object + * + * Returns the result set as an object + * + * @access private + * @return object + */ + function _fetch_object() + { + if (is_array($this->pdo_results)) + { + $i = $this->pdo_index; + $this->pdo_index++; + + if (isset($this->pdo_results[$i])) + { + $back = ''; + + foreach ($this->pdo_results[$i] as $key => $val) + { + $back->$key = $val; + } + + return $back; + } + + return null; + } + + return $this->result_id->fetch(PDO::FETCH_OBJ); + } +} ?> \ No newline at end of file diff --git a/system/database/drivers/postgre/index.html b/system/database/drivers/postgre/index.html index c942a79..065d2da 100644 --- a/system/database/drivers/postgre/index.html +++ b/system/database/drivers/postgre/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index b8ea9bc..bd98455 100644 --- a/system/database/drivers/postgre/postgre_driver.php +++ b/system/database/drivers/postgre/postgre_driver.php @@ -1,684 +1,684 @@ - '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(); - 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_char); - } - - 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).")"; - } - - // -------------------------------------------------------------------- - - /** - * 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 */ + '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(); + 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_char); + } + + 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).")"; + } + + // -------------------------------------------------------------------- + + /** + * 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 index 12eef29..3ebc982 100644 --- a/system/database/drivers/postgre/postgre_forge.php +++ b/system/database/drivers/postgre/postgre_forge.php @@ -1,248 +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\tFOREIGN KEY (" . implode(', ', $key) . ")"; - } - } - - $sql .= "\n);"; - - return $sql; - } - - // -------------------------------------------------------------------- - - /** - * Drop Table - * - * @access private - * @return bool - */ - function _drop_table($table) - { - return "DROP TABLE ".$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 */ +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) + { + return "DROP TABLE ".$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 index b8821ce..19d319d 100644 --- a/system/database/drivers/postgre/postgre_result.php +++ b/system/database/drivers/postgre/postgre_result.php @@ -1,169 +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 */ +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 index dda22dd..eaba0e0 100644 --- a/system/database/drivers/postgre/postgre_utility.php +++ b/system/database/drivers/postgre/postgre_utility.php @@ -1,124 +1,124 @@ -db->display_error('db_unsuported_feature'); - } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access private - * @param string the database name - * @return bool - */ - function _create_database($name) - { - return "CREATE DATABASE ".$name; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - return "DROP DATABASE ".$name; - } - - -} - - -/* End of file postgre_utility.php */ +db->display_error('db_unsuported_feature'); + } + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access private + * @param string the database name + * @return bool + */ + function _create_database($name) + { + return "CREATE DATABASE ".$name; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + return "DROP DATABASE ".$name; + } + + +} + + +/* 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 index c942a79..065d2da 100644 --- a/system/database/drivers/sqlite/index.html +++ b/system/database/drivers/sqlite/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 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 index 64a105f..8c13a09 100644 --- a/system/database/drivers/sqlite/sqlite_driver.php +++ b/system/database/drivers/sqlite/sqlite_driver.php @@ -1,657 +1,657 @@ -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(); - 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_char); - } - 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 */ +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(); + 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_char); + } + 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 index 1460c14..7ef15c7 100644 --- a/system/database/drivers/sqlite/sqlite_forge.php +++ b/system/database/drivers/sqlite/sqlite_forge.php @@ -1,265 +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->_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 */ +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->_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 index 607ce46..9a0b1ea 100644 --- a/system/database/drivers/sqlite/sqlite_result.php +++ b/system/database/drivers/sqlite/sqlite_result.php @@ -1,179 +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 */ +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 index 5629dac..d57fd7c 100644 --- a/system/database/drivers/sqlite/sqlite_utility.php +++ b/system/database/drivers/sqlite/sqlite_utility.php @@ -1,141 +1,141 @@ -db_debug) - { - return $this->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'); - } - - /** - * - * The functions below have been deprecated as of 1.6, and are only here for backwards - * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation - * is STRONGLY discouraged in favour if using dbforge. - * - */ - - /** - * Create database - * - * @access public - * @param string the database name - * @return bool - */ - function _create_database() - { - // In SQLite, a database is created when you connect to the database. - // We'll return TRUE so that an error isn't generated - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Drop database - * - * @access private - * @param string the database name - * @return bool - */ - function _drop_database($name) - { - if ( ! @file_exists($this->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; - } - -} - -/* End of file sqlite_utility.php */ +db_debug) + { + return $this->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'); + } + + /** + * + * The functions below have been deprecated as of 1.6, and are only here for backwards + * compatibility. They now reside in dbforge(). The use of dbutils for database manipulation + * is STRONGLY discouraged in favour if using dbforge. + * + */ + + /** + * Create database + * + * @access public + * @param string the database name + * @return bool + */ + function _create_database() + { + // In SQLite, a database is created when you connect to the database. + // We'll return TRUE so that an error isn't generated + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Drop database + * + * @access private + * @param string the database name + * @return bool + */ + function _drop_database($name) + { + if ( ! @file_exists($this->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; + } + +} + +/* 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/index.html b/system/database/index.html index c942a79..065d2da 100644 --- a/system/database/index.html +++ b/system/database/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 403 Forbidden + + + +

      Directory access is forbidden.

      + + \ No newline at end of file diff --git a/system/fonts/index.html b/system/fonts/index.html index c942a79..065d2da 100644 --- a/system/fonts/index.html +++ b/system/fonts/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

      Directory access is forbidden.

      - - + + + 403 Forbidden + + + +

      Directory access is forbidden.

      + + \ No newline at end of file diff --git a/system/helpers/array_helper.php b/system/helpers/array_helper.php index bd30b7c..0938583 100644 --- a/system/helpers/array_helper.php +++ b/system/helpers/array_helper.php @@ -1,78 +1,78 @@ - 0) // 8 = FILE_APPEND flag - { - $mode = FOPEN_WRITE_CREATE; - } - else - { - $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE; - } - - // Check if we're using the include path - if (($flags & 1) > 0) // 1 = FILE_USE_INCLUDE_PATH flag - { - $use_include_path = TRUE; - } - else - { - $use_include_path = FALSE; - } - - $fp = @fopen($filename, $mode, $use_include_path); - - if ($fp === FALSE) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') failed to open stream', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - if (($flags & LOCK_EX) > 0) - { - if ( ! flock($fp, LOCK_EX)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') unable to acquire an exclusive lock on file', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - } - - // write it - if (($written = @fwrite($fp, $data)) === FALSE) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') failed to write to '.htmlentities($filename), $backtrace[0]['file'], $backtrace[0]['line']); - } - - // Close the handle - @fclose($fp); - - // Return length - return $written; - } -} - -// ------------------------------------------------------------------------ - -/** - * fputcsv() - * - * Format line as CSV and write to file pointer - * http://us.php.net/manual/en/function.fputcsv.php - * - * @access public - * @param resource file pointer - * @param array data to be written - * @param string delimiter - * @param string enclosure - * @return int length of written string - */ -if ( ! function_exists('fputcsv')) -{ - function fputcsv($handle, $fields, $delimiter = ',', $enclosure = '"') - { - // Checking for a handle resource - if ( ! is_resource($handle)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 1 to be stream resource, '.gettype($handle).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // OK, it is a resource, but is it a stream? - if (get_resource_type($handle) !== 'stream') - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 1 to be stream resource, '.get_resource_type($handle).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // Checking for an array of fields - if ( ! is_array($fields)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 2 to be array, '.gettype($fields).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // validate delimiter - if (strlen($delimiter) > 1) - { - $delimiter = substr($delimiter, 0, 1); - $backtrace = debug_backtrace(); - _exception_handler(E_NOTICE, 'fputcsv() delimiter must be one character long, "'.htmlentities($delimiter).'" used', $backtrace[0]['file'], $backtrace[0]['line']); - } - - // validate enclosure - if (strlen($enclosure) > 1) - { - $enclosure = substr($enclosure, 0, 1); - $backtrace = debug_backtrace(); - _exception_handler(E_NOTICE, 'fputcsv() enclosure must be one character long, "'.htmlentities($enclosure).'" used', $backtrace[0]['file'], $backtrace[0]['line']); - - } - - $out = ''; - - foreach ($fields as $cell) - { - $cell = str_replace($enclosure, $enclosure.$enclosure, $cell); - - if (strpos($cell, $delimiter) !== FALSE OR strpos($cell, $enclosure) !== FALSE OR strpos($cell, "\n") !== FALSE) - { - $out .= $enclosure.$cell.$enclosure.$delimiter; - } - else - { - $out .= $cell.$delimiter; - } - } - - $length = @fwrite($handle, substr($out, 0, -1)."\n"); - - return $length; - } -} - -// ------------------------------------------------------------------------ - -/** - * stripos() - * - * Find position of first occurrence of a case-insensitive string - * http://us.php.net/manual/en/function.stripos.php - * - * @access public - * @param string haystack - * @param string needle - * @param int offset - * @return int numeric position of the first occurrence of needle in the haystack - */ -if ( ! function_exists('stripos')) -{ - function stripos($haystack, $needle, $offset = NULL) - { - // Cast non string scalar values - if (is_scalar($haystack)) - { - settype($haystack, 'STRING'); - } - - if ( ! is_string($haystack)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'stripos() expects parameter 1 to be string, '.gettype($haystack).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - if ( ! is_scalar($needle)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'stripos() needle is not a string or an integer in '.$backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - if (is_float($offset)) - { - $offset = (int)$offset; - } - - if ( ! is_int($offset) && ! is_bool($offset) && ! is_null($offset)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'stripos() expects parameter 3 to be long, '.gettype($offset).' given', $backtrace[0]['file'], $backtrace[0]['line']); - return NULL; - } - - return strpos(strtolower($haystack), strtolower($needle), $offset); - } -} - -// ------------------------------------------------------------------------ - -/** - * str_ireplace() - * - * Find position of first occurrence of a case-insensitive string - * http://us.php.net/manual/en/function.str-ireplace.php - * (parameter 4, $count, is not supported as to do so in PHP 4 would make - * it a required parameter) - * - * @access public - * @param mixed search - * @param mixed replace - * @param mixed subject - * @return int numeric position of the first occurrence of needle in the haystack - */ -if ( ! function_exists('str_ireplace')) -{ - function str_ireplace($search, $replace, $subject) - { - // Nothing to do here - if ($search === NULL OR $subject === NULL) - { - return $subject; - } - - // Crazy arguments - if (is_scalar($search) && is_array($replace)) - { - $backtrace = debug_backtrace(); - - if (is_object($replace)) - { - show_error('Object of class '.get_class($replace).' could not be converted to string in '.$backtrace[0]['file'].' on line '.$backtrace[0]['line']); - } - else - { - _exception_handler(E_USER_NOTICE, 'Array to string conversion in '.$backtrace[0]['file'], $backtrace[0]['line']); - } - } - - // Searching for an array - if (is_array($search)) - { - // Replacing with an array - if (is_array($replace)) - { - $search = array_values($search); - $replace = array_values($replace); - - if (count($search) >= count($replace)) - { - $replace = array_pad($replace, count($search), ''); - } - else - { - $replace = array_slice($replace, 0, count($search)); - } - } - else - { - // Replacing with a string all positions - $replace = array_fill(0, count($search), $replace); - } - } - else - { - //Searching for a string and replacing with a string. - $search = array((string)$search); - $replace = array((string)$replace); - } - - // Prepare the search array - foreach ($search as $search_key => $search_value) - { - $search[$search_key] = '/'.preg_quote($search_value, '/').'/i'; - } - - // Prepare the replace array (escape backreferences) - foreach ($replace as $k => $v) - { - $replace[$k] = str_replace(array(chr(92), '$'), array(chr(92).chr(92), '\$'), $v); - } - - // do the replacement - $result = preg_replace($search, $replace, (array)$subject); - - // Check if subject was initially a string and return it as a string - if ( ! is_array($subject)) - { - return current($result); - } - - // Otherwise, just return the array - return $result; - } -} - -// ------------------------------------------------------------------------ - -/** - * http_build_query() - * - * Generate URL-encoded query string - * http://us.php.net/manual/en/function.http-build-query.php - * - * @access public - * @param array form data - * @param string numeric prefix - * @param string argument separator - * @return string URL-encoded string - */ -if ( ! function_exists('http_build_query')) -{ - function http_build_query($formdata, $numeric_prefix = NULL, $separator = NULL) - { - // Check the data - if ( ! is_array($formdata) && ! is_object($formdata)) - { - $backtrace = debug_backtrace(); - _exception_handler(E_USER_WARNING, 'http_build_query() Parameter 1 expected to be Array or Object. Incorrect value given', $backtrace[0]['file'], $backtrace[0]['line']); - return FALSE; - } - - // Cast it as array - if (is_object($formdata)) - { - $formdata = get_object_vars($formdata); - } - - // If the array is empty, return NULL - if (empty($formdata)) - { - return NULL; - } - - // Argument separator - if ($separator === NULL) - { - $separator = ini_get('arg_separator.output'); - - if (strlen($separator) == 0) - { - $separator = '&'; - } - } - - // Start building the query - $tmp = array(); - - foreach ($formdata as $key => $val) - { - if ($val === NULL) - { - continue; - } - - if (is_integer($key) && $numeric_prefix != NULL) - { - $key = $numeric_prefix.$key; - } - - if (is_resource($val)) - { - return NULL; - } - - // hand it off to a recursive parser - $tmp[] = _http_build_query_helper($key, $val, $separator); - } - - return implode($separator, $tmp); - } - - - // Helper helper. Remind anyone of college? - // Required to handle recursion in nested arrays. - // - // You could shave fractions of fractions of a second by moving where - // the urlencoding takes place, but it's much less intuitive, and if - // your application has 10,000 form fields, well, you have other problems ;) - function _http_build_query_helper($key, $val, $separator = '&') - { - if (is_scalar($val)) - { - return urlencode($key).'='.urlencode($val); - } - else - { - // arrays please - if (is_object($val)) - { - $val = get_object_vars($val); - } - - foreach ($val as $k => $v) - { - $tmp[] = _http_build_query_helper($key.'['.$k.']', $v, $separator); - } - } - - return implode($separator, $tmp); - } -} - - -/* End of file compatibility_helper.php */ + 0) // 8 = FILE_APPEND flag + { + $mode = FOPEN_WRITE_CREATE; + } + else + { + $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE; + } + + // Check if we're using the include path + if (($flags & 1) > 0) // 1 = FILE_USE_INCLUDE_PATH flag + { + $use_include_path = TRUE; + } + else + { + $use_include_path = FALSE; + } + + $fp = @fopen($filename, $mode, $use_include_path); + + if ($fp === FALSE) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') failed to open stream', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + if (($flags & LOCK_EX) > 0) + { + if ( ! flock($fp, LOCK_EX)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') unable to acquire an exclusive lock on file', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + } + + // write it + if (($written = @fwrite($fp, $data)) === FALSE) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'file_put_contents('.htmlentities($filename).') failed to write to '.htmlentities($filename), $backtrace[0]['file'], $backtrace[0]['line']); + } + + // Close the handle + @fclose($fp); + + // Return length + return $written; + } +} + +// ------------------------------------------------------------------------ + +/** + * fputcsv() + * + * Format line as CSV and write to file pointer + * http://us.php.net/manual/en/function.fputcsv.php + * + * @access public + * @param resource file pointer + * @param array data to be written + * @param string delimiter + * @param string enclosure + * @return int length of written string + */ +if ( ! function_exists('fputcsv')) +{ + function fputcsv($handle, $fields, $delimiter = ',', $enclosure = '"') + { + // Checking for a handle resource + if ( ! is_resource($handle)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 1 to be stream resource, '.gettype($handle).' given', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + // OK, it is a resource, but is it a stream? + if (get_resource_type($handle) !== 'stream') + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 1 to be stream resource, '.get_resource_type($handle).' given', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + // Checking for an array of fields + if ( ! is_array($fields)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'fputcsv() expects parameter 2 to be array, '.gettype($fields).' given', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + // validate delimiter + if (strlen($delimiter) > 1) + { + $delimiter = substr($delimiter, 0, 1); + $backtrace = debug_backtrace(); + _exception_handler(E_NOTICE, 'fputcsv() delimiter must be one character long, "'.htmlentities($delimiter).'" used', $backtrace[0]['file'], $backtrace[0]['line']); + } + + // validate enclosure + if (strlen($enclosure) > 1) + { + $enclosure = substr($enclosure, 0, 1); + $backtrace = debug_backtrace(); + _exception_handler(E_NOTICE, 'fputcsv() enclosure must be one character long, "'.htmlentities($enclosure).'" used', $backtrace[0]['file'], $backtrace[0]['line']); + + } + + $out = ''; + + foreach ($fields as $cell) + { + $cell = str_replace($enclosure, $enclosure.$enclosure, $cell); + + if (strpos($cell, $delimiter) !== FALSE OR strpos($cell, $enclosure) !== FALSE OR strpos($cell, "\n") !== FALSE) + { + $out .= $enclosure.$cell.$enclosure.$delimiter; + } + else + { + $out .= $cell.$delimiter; + } + } + + $length = @fwrite($handle, substr($out, 0, -1)."\n"); + + return $length; + } +} + +// ------------------------------------------------------------------------ + +/** + * stripos() + * + * Find position of first occurrence of a case-insensitive string + * http://us.php.net/manual/en/function.stripos.php + * + * @access public + * @param string haystack + * @param string needle + * @param int offset + * @return int numeric position of the first occurrence of needle in the haystack + */ +if ( ! function_exists('stripos')) +{ + function stripos($haystack, $needle, $offset = NULL) + { + // Cast non string scalar values + if (is_scalar($haystack)) + { + settype($haystack, 'STRING'); + } + + if ( ! is_string($haystack)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'stripos() expects parameter 1 to be string, '.gettype($haystack).' given', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + if ( ! is_scalar($needle)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'stripos() needle is not a string or an integer in '.$backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + if (is_float($offset)) + { + $offset = (int)$offset; + } + + if ( ! is_int($offset) && ! is_bool($offset) && ! is_null($offset)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'stripos() expects parameter 3 to be long, '.gettype($offset).' given', $backtrace[0]['file'], $backtrace[0]['line']); + return NULL; + } + + return strpos(strtolower($haystack), strtolower($needle), $offset); + } +} + +// ------------------------------------------------------------------------ + +/** + * str_ireplace() + * + * Find position of first occurrence of a case-insensitive string + * http://us.php.net/manual/en/function.str-ireplace.php + * (parameter 4, $count, is not supported as to do so in PHP 4 would make + * it a required parameter) + * + * @access public + * @param mixed search + * @param mixed replace + * @param mixed subject + * @return int numeric position of the first occurrence of needle in the haystack + */ +if ( ! function_exists('str_ireplace')) +{ + function str_ireplace($search, $replace, $subject) + { + // Nothing to do here + if ($search === NULL OR $subject === NULL) + { + return $subject; + } + + // Crazy arguments + if (is_scalar($search) && is_array($replace)) + { + $backtrace = debug_backtrace(); + + if (is_object($replace)) + { + show_error('Object of class '.get_class($replace).' could not be converted to string in '.$backtrace[0]['file'].' on line '.$backtrace[0]['line']); + } + else + { + _exception_handler(E_USER_NOTICE, 'Array to string conversion in '.$backtrace[0]['file'], $backtrace[0]['line']); + } + } + + // Searching for an array + if (is_array($search)) + { + // Replacing with an array + if (is_array($replace)) + { + $search = array_values($search); + $replace = array_values($replace); + + if (count($search) >= count($replace)) + { + $replace = array_pad($replace, count($search), ''); + } + else + { + $replace = array_slice($replace, 0, count($search)); + } + } + else + { + // Replacing with a string all positions + $replace = array_fill(0, count($search), $replace); + } + } + else + { + //Searching for a string and replacing with a string. + $search = array((string)$search); + $replace = array((string)$replace); + } + + // Prepare the search array + foreach ($search as $search_key => $search_value) + { + $search[$search_key] = '/'.preg_quote($search_value, '/').'/i'; + } + + // Prepare the replace array (escape backreferences) + foreach ($replace as $k => $v) + { + $replace[$k] = str_replace(array(chr(92), '$'), array(chr(92).chr(92), '\$'), $v); + } + + // do the replacement + $result = preg_replace($search, $replace, (array)$subject); + + // Check if subject was initially a string and return it as a string + if ( ! is_array($subject)) + { + return current($result); + } + + // Otherwise, just return the array + return $result; + } +} + +// ------------------------------------------------------------------------ + +/** + * http_build_query() + * + * Generate URL-encoded query string + * http://us.php.net/manual/en/function.http-build-query.php + * + * @access public + * @param array form data + * @param string numeric prefix + * @param string argument separator + * @return string URL-encoded string + */ +if ( ! function_exists('http_build_query')) +{ + function http_build_query($formdata, $numeric_prefix = NULL, $separator = NULL) + { + // Check the data + if ( ! is_array($formdata) && ! is_object($formdata)) + { + $backtrace = debug_backtrace(); + _exception_handler(E_USER_WARNING, 'http_build_query() Parameter 1 expected to be Array or Object. Incorrect value given', $backtrace[0]['file'], $backtrace[0]['line']); + return FALSE; + } + + // Cast it as array + if (is_object($formdata)) + { + $formdata = get_object_vars($formdata); + } + + // If the array is empty, return NULL + if (empty($formdata)) + { + return NULL; + } + + // Argument separator + if ($separator === NULL) + { + $separator = ini_get('arg_separator.output'); + + if (strlen($separator) == 0) + { + $separator = '&'; + } + } + + // Start building the query + $tmp = array(); + + foreach ($formdata as $key => $val) + { + if ($val === NULL) + { + continue; + } + + if (is_integer($key) && $numeric_prefix != NULL) + { + $key = $numeric_prefix.$key; + } + + if (is_resource($val)) + { + return NULL; + } + + // hand it off to a recursive parser + $tmp[] = _http_build_query_helper($key, $val, $separator); + } + + return implode($separator, $tmp); + } + + + // Helper helper. Remind anyone of college? + // Required to handle recursion in nested arrays. + // + // You could shave fractions of fractions of a second by moving where + // the urlencoding takes place, but it's much less intuitive, and if + // your application has 10,000 form fields, well, you have other problems ;) + function _http_build_query_helper($key, $val, $separator = '&') + { + if (is_scalar($val)) + { + return urlencode($key).'='.urlencode($val); + } + else + { + // arrays please + if (is_object($val)) + { + $val = get_object_vars($val); + } + + foreach ($val as $k => $v) + { + $tmp[] = _http_build_query_helper($key.'['.$k.']', $v, $separator); + } + } + + return implode($separator, $tmp); + } +} + + +/* End of file compatibility_helper.php */ /* Location: ./system/helpers/compatibility_helper.php */ \ No newline at end of file diff --git a/system/helpers/cookie_helper.php b/system/helpers/cookie_helper.php index bcd0fa2..7cb8954 100644 --- a/system/helpers/cookie_helper.php +++ b/system/helpers/cookie_helper.php @@ -1,144 +1,144 @@ -config->item('cookie_prefix') != '') - { - $prefix = $CI->config->item('cookie_prefix'); - } - if ($domain == '' AND $CI->config->item('cookie_domain') != '') - { - $domain = $CI->config->item('cookie_domain'); - } - if ($path == '/' AND $CI->config->item('cookie_path') != '/') - { - $path = $CI->config->item('cookie_path'); - } - - if ( ! is_numeric($expire)) - { - $expire = time() - 86500; - } - else - { - if ($expire > 0) - { - $expire = time() + $expire; - } - else - { - $expire = 0; - } - } - - setcookie($prefix.$name, $value, $expire, $path, $domain, 0); - } -} - -// -------------------------------------------------------------------- - -/** - * 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 */ +config->item('cookie_prefix') != '') + { + $prefix = $CI->config->item('cookie_prefix'); + } + if ($domain == '' AND $CI->config->item('cookie_domain') != '') + { + $domain = $CI->config->item('cookie_domain'); + } + if ($path == '/' AND $CI->config->item('cookie_path') != '/') + { + $path = $CI->config->item('cookie_path'); + } + + if ( ! is_numeric($expire)) + { + $expire = time() - 86500; + } + else + { + if ($expire > 0) + { + $expire = time() + $expire; + } + else + { + $expire = 0; + } + } + + setcookie($prefix.$name, $value, $expire, $path, $domain, 0); + } +} + +// -------------------------------------------------------------------- + +/** + * 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 index 0dd5e09..57d34f8 100644 --- a/system/helpers/date_helper.php +++ b/system/helpers/date_helper.php @@ -1,611 +1,609 @@ -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%O', - 'DATE_RFC822' => '%D, %d %M %y %H:%i:%s %O', - 'DATE_RFC850' => '%l, %d-%M-%y %H:%m:%i 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+/", "\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 = preg_split("/\040/", $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 */ +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%O', + 'DATE_RFC822' => '%D, %d %M %y %H:%i:%s %O', + 'DATE_RFC850' => '%l, %d-%M-%y %H:%m:%i 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(); + + 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.' '.T_((($years > 1) ? 'date_years' : 'date_year')).', '; + } + + $seconds -= $years * 31536000; + $months = floor($seconds / 2628000); + + if ($years > 0 OR $months > 0) + { + if ($months > 0) + { + $str .= $months.' '.T_((($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.' '.T_((($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.' '.T_((($days > 1) ? 'date_days' : 'date_day')).', '; + } + + $seconds -= $days * 86400; + } + + $hours = floor($seconds / 3600); + + if ($days > 0 OR $hours > 0) + { + if ($hours > 0) + { + $str .= $hours.' '.T_((($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.' '.T_((($minutes > 1) ? 'date_minutes' : 'date_minute')).', '; + } + + $seconds -= $minutes * 60; + } + + if ($str == '') + { + $str .= $seconds.' '.T_((($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+/", "\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 = preg_split("/\040/", $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(); + + 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 index 4c5aba4..eb90124 100644 --- a/system/helpers/directory_helper.php +++ b/system/helpers/directory_helper.php @@ -1,84 +1,84 @@ - 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; - - 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) - { - @rmdir($path); - } - } -} - -// ------------------------------------------------------------------------ - -/** - * 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 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_dir_file_info')) -{ - function get_dir_file_info($source_dir, $include_path = FALSE, $_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; - } - - while (FALSE !== ($file = readdir($fp))) - { - if (@is_dir($source_dir.$file) && strncmp($file, '.', 1) !== 0) - { - get_dir_file_info($source_dir.$file.DIRECTORY_SEPARATOR, $include_path, 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'] = filectime($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 = substr(strrchr($file, '.'), 1); - - global $mimes; - - if ( ! is_array($mimes)) - { - if ( ! require_once(APPPATH.'config/mimes.php')) - { - 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 */ + 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; + + 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) + { + @rmdir($path); + } + } +} + +// ------------------------------------------------------------------------ + +/** + * 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 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_dir_file_info')) +{ + function get_dir_file_info($source_dir, $include_path = FALSE, $_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; + } + + while (FALSE !== ($file = readdir($fp))) + { + if (@is_dir($source_dir.$file) && strncmp($file, '.', 1) !== 0) + { + get_dir_file_info($source_dir.$file.DIRECTORY_SEPARATOR, $include_path, 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'] = filectime($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 = substr(strrchr($file, '.'), 1); + + global $mimes; + + if ( ! is_array($mimes)) + { + if ( ! require_once(APPPATH.'config/mimes.php')) + { + 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 index 7afab7b..97cc06d 100644 --- a/system/helpers/form_helper.php +++ b/system/helpers/form_helper.php @@ -1,1025 +1,1025 @@ -config->site_url($action) : $action; - - $form = '
      0) - { - $form .= 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()) - { - $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' => '90', 'rows' => '12'); - - 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] = $str; - } - - 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 '."\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' => '90', 'rows' => '12'); + + 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] = $str; + } + + 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 */ +CI =& get_instance(); + + $this->local_time = time(); + + if (count($config) > 0) + { + $this->initialize($config); + } + + log_message('debug', "Calendar Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize the user preferences + * + * Accepts an associative array as input, containing display preferences + * + * @access public + * @param array config preferences + * @return void + */ + function initialize($config = array()) + { + foreach ($config as $key => $val) + { + if (isset($this->$key)) + { + $this->$key = $val; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Generate the calendar + * + * @access public + * @param integer the year + * @param integer the month + * @param array the data to be shown in the calendar cells + * @return string + */ + function generate($year = '', $month = '', $data = array()) + { + // Set and validate the supplied month/year + if ($year == '') + $year = date("Y", $this->local_time); + + if ($month == '') + $month = date("m", $this->local_time); + + if (strlen($year) == 1) + $year = '200'.$year; + + if (strlen($year) == 2) + $year = '20'.$year; + + if (strlen($month) == 1) + $month = '0'.$month; + + $adjusted_date = $this->adjust_date($month, $year); + + $month = $adjusted_date['month']; + $year = $adjusted_date['year']; + + // Determine the total days in the month + $total_days = $this->get_total_days($month, $year); + + // Set the starting day of the week + $start_days = array('sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6); + $start_day = ( ! isset($start_days[$this->start_day])) ? 0 : $start_days[$this->start_day]; + + // Set the starting day number + $local_date = mktime(12, 0, 0, $month, 1, $year); + $date = getdate($local_date); + $day = $start_day + 1 - $date["wday"]; + + while ($day > 1) + { + $day -= 7; + } + + // Set the current month/year/day + // We use this to determine the "today" date + $cur_year = date("Y", $this->local_time); + $cur_month = date("m", $this->local_time); + $cur_day = date("j", $this->local_time); + + $is_current_month = ($cur_year == $year AND $cur_month == $month) ? TRUE : FALSE; + + // Generate the template data array + $this->parse_template(); + + // Begin building the calendar output + $out = $this->temp['table_open']; + $out .= "\n"; + + $out .= "\n"; + $out .= $this->temp['heading_row_start']; + $out .= "\n"; + + // "previous" month link + if ($this->show_next_prev == TRUE) + { + // Add a trailing slash to the URL if needed + $this->next_prev_url = preg_replace("/(.+?)\/*$/", "\\1/", $this->next_prev_url); + + $adjusted_date = $this->adjust_date($month - 1, $year); + $out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_previous_cell']); + $out .= "\n"; + } + + // Heading containing the month/year + $colspan = ($this->show_next_prev == TRUE) ? 5 : 7; + + $this->temp['heading_title_cell'] = str_replace('{colspan}', $colspan, $this->temp['heading_title_cell']); + $this->temp['heading_title_cell'] = str_replace('{heading}', $this->get_month_name($month)." ".$year, $this->temp['heading_title_cell']); + + $out .= $this->temp['heading_title_cell']; + $out .= "\n"; + + // "next" month link + if ($this->show_next_prev == TRUE) + { + $adjusted_date = $this->adjust_date($month + 1, $year); + $out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_next_cell']); + } + + $out .= "\n"; + $out .= $this->temp['heading_row_end']; + $out .= "\n"; + + // Write the cells containing the days of the week + $out .= "\n"; + $out .= $this->temp['week_row_start']; + $out .= "\n"; + + $day_names = $this->get_day_names(); + + for ($i = 0; $i < 7; $i ++) + { + $out .= str_replace('{week_day}', $day_names[($start_day + $i) %7], $this->temp['week_day_cell']); + } + + $out .= "\n"; + $out .= $this->temp['week_row_end']; + $out .= "\n"; + + // Build the main body of the calendar + while ($day <= $total_days) + { + $out .= "\n"; + $out .= $this->temp['cal_row_start']; + $out .= "\n"; + + for ($i = 0; $i < 7; $i++) + { + $out .= ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start']; + + if ($day > 0 AND $day <= $total_days) + { + if (isset($data[$day])) + { + // Cells with content + $temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_content_today'] : $this->temp['cal_cell_content']; + $out .= str_replace('{day}', $day, str_replace('{content}', $data[$day], $temp)); + } + else + { + // Cells with no content + $temp = ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_no_content_today'] : $this->temp['cal_cell_no_content']; + $out .= str_replace('{day}', $day, $temp); + } + } + else + { + // Blank cells + $out .= $this->temp['cal_cell_blank']; + } + + $out .= ($is_current_month == TRUE AND $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end']; + $day++; + } + + $out .= "\n"; + $out .= $this->temp['cal_row_end']; + $out .= "\n"; + } + + $out .= "\n"; + $out .= $this->temp['table_close']; + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * Get Month Name + * + * Generates a textual month name based on the numeric + * month provided. + * + * @access public + * @param integer the month + * @return string + */ + function get_month_name($month) + { + if ($this->month_type == 'short') + { + $month_names = array('01' => 'cal_jan', '02' => 'cal_feb', '03' => 'cal_mar', '04' => 'cal_apr', '05' => 'cal_may', '06' => 'cal_jun', '07' => 'cal_jul', '08' => 'cal_aug', '09' => 'cal_sep', '10' => 'cal_oct', '11' => 'cal_nov', '12' => 'cal_dec'); + } + else + { + $month_names = array('01' => 'cal_january', '02' => 'cal_february', '03' => 'cal_march', '04' => 'cal_april', '05' => 'cal_mayl', '06' => 'cal_june', '07' => 'cal_july', '08' => 'cal_august', '09' => 'cal_september', '10' => 'cal_october', '11' => 'cal_november', '12' => 'cal_december'); + } + + $month = $month_names[$month]; + + if (T_($month) === FALSE) + { + return ucfirst(str_replace('cal_', '', $month)); + } + + return T_($month); + } + + // -------------------------------------------------------------------- + + /** + * Get Day Names + * + * Returns an array of day names (Sunday, Monday, etc.) based + * on the type. Options: long, short, abrev + * + * @access public + * @param string + * @return array + */ + function get_day_names($day_type = '') + { + if ($day_type != '') + $this->day_type = $day_type; + + if ($this->day_type == 'long') + { + $day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); + } + elseif ($this->day_type == 'short') + { + $day_names = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); + } + else + { + $day_names = array('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa'); + } + + $days = array(); + foreach ($day_names as $val) + { + $days[] = (T_('cal_'.$val) === FALSE) ? ucfirst($val) : T_('cal_'.$val); + } + + return $days; + } + + // -------------------------------------------------------------------- + + /** + * Adjust Date + * + * This function makes sure that we have a valid month/year. + * For example, if you submit 13 as the month, the year will + * increment and the month will become January. + * + * @access public + * @param integer the month + * @param integer the year + * @return array + */ + function adjust_date($month, $year) + { + $date = array(); + + $date['month'] = $month; + $date['year'] = $year; + + while ($date['month'] > 12) + { + $date['month'] -= 12; + $date['year']++; + } + + while ($date['month'] <= 0) + { + $date['month'] += 12; + $date['year']--; + } + + if (strlen($date['month']) == 1) + { + $date['month'] = '0'.$date['month']; + } + + return $date; + } + + // -------------------------------------------------------------------- + + /** + * Total days in a given month + * + * @access public + * @param integer the month + * @param integer the year + * @return integer + */ + function get_total_days($month, $year) + { + $days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); + + if ($month < 1 OR $month > 12) + { + return 0; + } + + // Is the year a leap year? + if ($month == 2) + { + if ($year % 400 == 0 OR ($year % 4 == 0 AND $year % 100 != 0)) + { + return 29; + } + } + + return $days_in_month[$month - 1]; + } + + // -------------------------------------------------------------------- + + /** + * Set Default Template Data + * + * This is used in the event that the user has not created their own template + * + * @access public + * @return array + */ + function default_template() + { + return array ( + 'table_open' => '', + '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 index f3969ef..5fee2aa 100644 --- a/system/libraries/Cart.php +++ b/system/libraries/Cart.php @@ -1,550 +1,550 @@ -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 ($this->_insert($items) == TRUE) - { - $save_cart = TRUE; - } - } - else - { - foreach ($items as $val) - { - if (is_array($val) AND isset($val['id'])) - { - if ($this->_insert($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; - } - - // -------------------------------------------------------------------- - - /** - * 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 TRUE; - } - - // -------------------------------------------------------------------- - - /** - * 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; - 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']); - - // 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'] = count($this->_cart_contents); - $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 */ +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 ($this->_insert($items) == TRUE) + { + $save_cart = TRUE; + } + } + else + { + foreach ($items as $val) + { + if (is_array($val) AND isset($val['id'])) + { + if ($this->_insert($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; + } + + // -------------------------------------------------------------------- + + /** + * 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 TRUE; + } + + // -------------------------------------------------------------------- + + /** + * 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; + 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']); + + // 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'] = count($this->_cart_contents); + $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/Config.php b/system/libraries/Config.php index b7f5046..c6d78b1 100644 --- a/system/libraries/Config.php +++ b/system/libraries/Config.php @@ -1,244 +1,244 @@ -config =& get_config(); - log_message('debug', "Config Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Load Config File - * - * @access public - * @param string the config file name - * @return boolean if the file was loaded correctly - */ - function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) - { - $file = ($file == '') ? 'config' : str_replace(EXT, '', $file); - - if (in_array($file, $this->is_loaded, TRUE)) - { - return TRUE; - } - - if ( ! file_exists(APPPATH.'config/'.$file.EXT)) - { - if ($fail_gracefully === TRUE) - { - return FALSE; - } - show_error('The configuration file '.$file.EXT.' does not exist.'); - } - - include(APPPATH.'config/'.$file.EXT); - - if ( ! isset($config) OR ! is_array($config)) - { - if ($fail_gracefully === TRUE) - { - return FALSE; - } - show_error('Your '.$file.EXT.' 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; - unset($config); - - log_message('debug', 'Config file loaded: config/'.$file.EXT); - 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 - * - * The second parameter allows a slash to be added to the end of - * the item, in the case of a path. - * - * @access public - * @param string the config item name - * @param bool - * @return string - */ - function slash_item($item) - { - if ( ! isset($this->config[$item])) - { - return FALSE; - } - - $pref = $this->config[$item]; - - if ($pref != '' && substr($pref, -1) != '/') - { - $pref .= '/'; - } - - return $pref; - } - - // -------------------------------------------------------------------- - - /** - * Site URL - * - * @access public - * @param string the URI string - * @return string - */ - function site_url($uri = '') - { - if (is_array($uri)) - { - $uri = implode('/', $uri); - } - - if ($uri == '') - { - return $this->slash_item('base_url').$this->item('index_page'); - } - else - { - $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix'); - return $this->slash_item('base_url').$this->slash_item('index_page').trim($uri, '/').$suffix; - } - } - - // -------------------------------------------------------------------- - - /** - * 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; - } - -} - -// END CI_Config class - -/* End of file Config.php */ +config =& get_config(); + log_message('debug', "Config Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Load Config File + * + * @access public + * @param string the config file name + * @return boolean if the file was loaded correctly + */ + function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) + { + $file = ($file == '') ? 'config' : str_replace(EXT, '', $file); + + if (in_array($file, $this->is_loaded, TRUE)) + { + return TRUE; + } + + if ( ! file_exists(APPPATH.'config/'.$file.EXT)) + { + if ($fail_gracefully === TRUE) + { + return FALSE; + } + show_error('The configuration file '.$file.EXT.' does not exist.'); + } + + include(APPPATH.'config/'.$file.EXT); + + if ( ! isset($config) OR ! is_array($config)) + { + if ($fail_gracefully === TRUE) + { + return FALSE; + } + show_error('Your '.$file.EXT.' 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; + unset($config); + + log_message('debug', 'Config file loaded: config/'.$file.EXT); + 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 + * + * The second parameter allows a slash to be added to the end of + * the item, in the case of a path. + * + * @access public + * @param string the config item name + * @param bool + * @return string + */ + function slash_item($item) + { + if ( ! isset($this->config[$item])) + { + return FALSE; + } + + $pref = $this->config[$item]; + + if ($pref != '' && substr($pref, -1) != '/') + { + $pref .= '/'; + } + + return $pref; + } + + // -------------------------------------------------------------------- + + /** + * Site URL + * + * @access public + * @param string the URI string + * @return string + */ + function site_url($uri = '') + { + if (is_array($uri)) + { + $uri = implode('/', $uri); + } + + if ($uri == '') + { + return $this->slash_item('base_url').$this->item('index_page'); + } + else + { + $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix'); + return $this->slash_item('base_url').$this->slash_item('index_page').trim($uri, '/').$suffix; + } + } + + // -------------------------------------------------------------------- + + /** + * 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; + } + +} + +// END CI_Config class + +/* End of file Config.php */ /* Location: ./system/libraries/Config.php */ \ No newline at end of file diff --git a/system/libraries/Controller.php b/system/libraries/Controller.php index 9c6323c..3710999 100644 --- a/system/libraries/Controller.php +++ b/system/libraries/Controller.php @@ -1,127 +1,127 @@ -_ci_initialize(); - log_message('debug', "Controller Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Initialize - * - * Assigns all the bases classes loaded by the front controller to - * variables in this class. Also calls the autoload routine. - * - * @access private - * @return void - */ - function _ci_initialize() - { - // Assign all the class objects that were instantiated by the - // front controller to local class variables so that CI can be - // run as one big super object. - $classes = array( - 'config' => 'Config', - 'input' => 'Input', - 'benchmark' => 'Benchmark', - 'uri' => 'URI', - 'output' => 'Output', - 'lang' => 'Language', - 'router' => 'Router' - ); - - foreach ($classes as $var => $class) - { - $this->$var =& load_class($class); - } - - // In PHP 5 the Loader class is run as a discreet - // class. In PHP 4 it extends the Controller - if (floor(phpversion()) >= 5) - { - $this->load =& load_class('Loader'); - $this->load->_ci_autoloader(); - } - else - { - $this->_ci_autoloader(); - - // sync up the objects since PHP4 was working from a copy - foreach (array_keys(get_object_vars($this)) as $attribute) - { - if (is_object($this->$attribute)) - { - $this->load->$attribute =& $this->$attribute; - } - } - } - } - - // -------------------------------------------------------------------- - - /** - * Run Scaffolding - * - * @access private - * @return void - */ - function _ci_scaffolding() - { - if ($this->_ci_scaffolding === FALSE OR $this->_ci_scaff_table === FALSE) - { - show_404('Scaffolding unavailable'); - } - - $method = ( ! in_array($this->uri->segment(3), array('add', 'insert', 'edit', 'update', 'view', 'delete', 'do_delete'), TRUE)) ? 'view' : $this->uri->segment(3); - - require_once(BASEPATH.'scaffolding/Scaffolding'.EXT); - $scaff = new Scaffolding($this->_ci_scaff_table); - $scaff->$method(); - } - - -} -// END _Controller class - -/* End of file Controller.php */ +_ci_initialize(); + log_message('debug', "Controller Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize + * + * Assigns all the bases classes loaded by the front controller to + * variables in this class. Also calls the autoload routine. + * + * @access private + * @return void + */ + function _ci_initialize() + { + // Assign all the class objects that were instantiated by the + // front controller to local class variables so that CI can be + // run as one big super object. + $classes = array( + 'config' => 'Config', + 'input' => 'Input', + 'benchmark' => 'Benchmark', + 'uri' => 'URI', + 'output' => 'Output', + 'lang' => 'Language', + 'router' => 'Router' + ); + + foreach ($classes as $var => $class) + { + $this->$var =& load_class($class); + } + + // In PHP 5 the Loader class is run as a discreet + // class. In PHP 4 it extends the Controller + if (floor(phpversion()) >= 5) + { + $this->load =& load_class('Loader'); + $this->load->_ci_autoloader(); + } + else + { + $this->_ci_autoloader(); + + // sync up the objects since PHP4 was working from a copy + foreach (array_keys(get_object_vars($this)) as $attribute) + { + if (is_object($this->$attribute)) + { + $this->load->$attribute =& $this->$attribute; + } + } + } + } + + // -------------------------------------------------------------------- + + /** + * Run Scaffolding + * + * @access private + * @return void + */ + function _ci_scaffolding() + { + if ($this->_ci_scaffolding === FALSE OR $this->_ci_scaff_table === FALSE) + { + show_404('Scaffolding unavailable'); + } + + $method = ( ! in_array($this->uri->segment(3), array('add', 'insert', 'edit', 'update', 'view', 'delete', 'do_delete'), TRUE)) ? 'view' : $this->uri->segment(3); + + require_once(BASEPATH.'scaffolding/Scaffolding'.EXT); + $scaff = new Scaffolding($this->_ci_scaff_table); + $scaff->$method(); + } + + +} +// END _Controller class + +/* End of file Controller.php */ /* Location: ./system/libraries/Controller.php */ \ No newline at end of file diff --git a/system/libraries/Email.php b/system/libraries/Email.php index edfad7c..b888ab9 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1,2041 +1,2040 @@ - 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 - */ - function initialize($config = array()) - { - $this->clear(); - 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->_smtp_auth = ($this->smtp_user == '' AND $this->smtp_pass == '') ? FALSE : TRUE; - $this->_safe_mode = ((boolean)@ini_get("safe_mode") === FALSE) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Initialize the Email Data - * - * @access public - * @return void - */ - function clear($clear_attachments = FALSE) - { - $this->_subject = ""; - $this->_body = ""; - $this->_finalbody = ""; - $this->_header_str = ""; - $this->_replyto_flag = FALSE; - $this->_recipients = 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(); - } - } - - // -------------------------------------------------------------------- - - /** - * Set FROM - * - * @access public - * @param string - * @param string - * @return void - */ - 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.'>'); - } - - // -------------------------------------------------------------------- - - /** - * Set Reply-to - * - * @access public - * @param string - * @param string - * @return void - */ - 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; - } - - // -------------------------------------------------------------------- - - /** - * Set Recipients - * - * @access public - * @param string - * @return void - */ - 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' : $this->_recipients = implode(", ", $to); - break; - case 'mail' : $this->_recipients = implode(", ", $to); - break; - } - } - - // -------------------------------------------------------------------- - - /** - * Set CC - * - * @access public - * @param string - * @return void - */ - 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; - } - } - - // -------------------------------------------------------------------- - - /** - * Set BCC - * - * @access public - * @param string - * @param string - * @return void - */ - 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)); - } - } - - // -------------------------------------------------------------------- - - /** - * Set Email Subject - * - * @access public - * @param string - * @return void - */ - function subject($subject) - { - $subject = $this->_prep_q_encoding($subject); - $this->_set_header('Subject', $subject); - } - - // -------------------------------------------------------------------- - - /** - * Set Body - * - * @access public - * @param string - * @return void - */ - function message($body) - { - $this->_body = stripslashes(rtrim(str_replace("\r", "", $body))); - } - - // -------------------------------------------------------------------- - - /** - * Assign file attachments - * - * @access public - * @param string - * @return void - */ - function attach($filename, $disposition = 'attachment') - { - $this->_attach_name[] = $filename; - $this->_attach_type[] = $this->_mime_types(next(explode('.', basename($filename)))); - $this->_attach_disp[] = $disposition; // Can also be 'inline' Not sure if it matters - } - - // -------------------------------------------------------------------- - - /** - * Add a Header Item - * - * @access private - * @param string - * @param string - * @return void - */ - function _set_header($header, $value) - { - $this->_headers[$header] = $value; - } - - // -------------------------------------------------------------------- - - /** - * Convert a String to an Array - * - * @access private - * @param string - * @return array - */ - 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 - */ - function set_alt_message($str = '') - { - $this->alt_message = ($str == '') ? '' : $str; - } - - // -------------------------------------------------------------------- - - /** - * Set Mailtype - * - * @access public - * @param string - * @return void - */ - function set_mailtype($type = 'text') - { - $this->mailtype = ($type == 'html') ? 'html' : 'text'; - } - - // -------------------------------------------------------------------- - - /** - * Set Wordwrap - * - * @access public - * @param string - * @return void - */ - function set_wordwrap($wordwrap = TRUE) - { - $this->wordwrap = ($wordwrap === FALSE) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Set Protocol - * - * @access public - * @param string - * @return void - */ - function set_protocol($protocol = 'mail') - { - $this->protocol = ( ! in_array($protocol, $this->_protocols, TRUE)) ? 'mail' : strtolower($protocol); - } - - // -------------------------------------------------------------------- - - /** - * Set Priority - * - * @access public - * @param integer - * @return void - */ - 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; - } - - // -------------------------------------------------------------------- - - /** - * Set Newline Character - * - * @access public - * @param string - * @return void - */ - function set_newline($newline = "\n") - { - if ($newline != "\n" AND $newline != "\r\n" AND $newline != "\r") - { - $this->newline = "\n"; - return; - } - - $this->newline = $newline; - } - - // -------------------------------------------------------------------- - - /** - * Set CRLF - * - * @access public - * @param string - * @return void - */ - function set_crlf($crlf = "\n") - { - if ($crlf != "\n" AND $crlf != "\r\n" AND $crlf != "\r") - { - $this->crlf = "\n"; - return; - } - - $this->crlf = $crlf; - } - - // -------------------------------------------------------------------- - - /** - * Set Message Boundary - * - * @access private - * @return void - */ - function _set_boundaries() - { - $this->_alt_boundary = "B_ALT_".uniqid(''); // multipart/alternative - $this->_atc_boundary = "B_ATC_".uniqid(''); // attachment boundary - } - - // -------------------------------------------------------------------- - - /** - * Get the Message ID - * - * @access private - * @return string - */ - 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 private - * @param bool - * @return string - */ - 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 private - * @param bool - * @return string - */ - 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 private - * @return string - */ - 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 private - * @return string - */ - 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 private - * @return string - */ - 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 - */ - function validate_email($email) - { - if ( ! is_array($email)) - { - $this->_set_error_message('email_must_be_array'); - return FALSE; - } - - foreach ($email as $val) - { - if ( ! $this->valid_email($val)) - { - $this->_set_error_message('email_invalid_address', $val); - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Email Validation - * - * @access public - * @param string - * @return bool - */ - 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 - */ - 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 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 private - * @return string - */ - 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( '# '.$message. ' '.$filepath.' '.$line, TRUE); - } - - // -------------------------------------------------------------------- - - /** - * 404 Page Not Found Handler - * - * @access private - * @param string - * @return string - */ - function show_404($page = '') - { - $heading = "404 Page Not Found"; - $message = "The page you requested was not found."; - - 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 - * @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.EXT); - $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'.EXT); - $buffer = ob_get_contents(); - ob_end_clean(); - echo $buffer; - } - - -} -// END Exceptions Class - -/* End of file Exceptions.php */ + '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 + * + */ + function CI_Exceptions() + { + $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 + * @return string + */ + function show_404($page = '') + { + $heading = "404 Page Not Found"; + $message = "The page you requested was not found."; + + 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 + * @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.EXT); + $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'.EXT); + $buffer = ob_get_contents(); + ob_end_clean(); + echo $buffer; + } + + +} +// END Exceptions Class + +/* End of file Exceptions.php */ /* Location: ./system/libraries/Exceptions.php */ \ No newline at end of file diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index f7bb62c..7e677d9 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -1,1278 +1,1275 @@ -'; - var $_error_suffix = '

      '; - var $error_string = ''; - var $_safe_form_data = FALSE; - - - /** - * Constructor - * - */ - function CI_Form_validation($rules = array()) - { - $this->CI =& get_instance(); - - // Validation rules can be stored in a config file. - $this->_config_rules = $rules; - - // Automatically load the form helper - $this->CI->load->helper('form'); - - // Set the character encoding in MB. - if (function_exists('mb_internal_encoding')) - { - mb_internal_encoding($this->CI->config->item('charset')); - } - - log_message('debug', "Form Validation Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Set Rules - * - * This function takes an array of field names and validation - * rules as input, validates the info, and stores it - * - * @access public - * @param mixed - * @param string - * @return void - */ - function set_rules($field, $label = '', $rules = '') - { - // No reason to set rules if we have no POST data - if (count($_POST) == 0) - { - return; - } - - // If an array was passed via the first parameter instead of indidual string - // values we cycle through it and recursively call this function. - if (is_array($field)) - { - foreach ($field as $row) - { - // Houston, we have a problem... - if ( ! isset($row['field']) OR ! isset($row['rules'])) - { - continue; - } - - // If the field label wasn't passed we use the field name - $label = ( ! isset($row['label'])) ? $row['field'] : $row['label']; - - // Here we go! - $this->set_rules($row['field'], $label, $row['rules']); - } - return; - } - - // No fields? Nothing to do... - if ( ! is_string($field) OR ! is_string($rules) OR $field == '') - { - return; - } - - // If the field label wasn't passed we use the field name - $label = ($label == '') ? $field : $label; - - // Is the field name an array? We test for the existence of a bracket "[" in - // the field name to determine this. If it is an array, we break it apart - // into its components so that we can fetch the corresponding POST data later - if (strpos($field, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $field, $matches)) - { - // Note: Due to a bug in current() that affects some versions - // of PHP we can not pass function call directly into it - $x = explode('[', $field); - $indexes[] = current($x); - - for ($i = 0; $i < count($matches['0']); $i++) - { - if ($matches['1'][$i] != '') - { - $indexes[] = $matches['1'][$i]; - } - } - - $is_array = TRUE; - } - else - { - $indexes = array(); - $is_array = FALSE; - } - - // Build our master array - $this->_field_data[$field] = array( - 'field' => $field, - 'label' => $label, - 'rules' => $rules, - 'is_array' => $is_array, - 'keys' => $indexes, - 'postdata' => NULL, - 'error' => '' - ); - } - - // -------------------------------------------------------------------- - - /** - * Set Error Message - * - * Lets users set their own error messages on the fly. Note: The key - * name has to match the function name that it corresponds to. - * - * @access public - * @param string - * @param string - * @return string - */ - function set_message($lang, $val = '') - { - if ( ! is_array($lang)) - { - $lang = array($lang => $val); - } - - $this->_error_messages = array_merge($this->_error_messages, $lang); - } - - // -------------------------------------------------------------------- - - /** - * Set The Error Delimiter - * - * Permits a prefix/suffix to be added to each error message - * - * @access public - * @param string - * @param string - * @return void - */ - function set_error_delimiters($prefix = '

      ', $suffix = '

      ') - { - $this->_error_prefix = $prefix; - $this->_error_suffix = $suffix; - } - - // -------------------------------------------------------------------- - - /** - * Get Error Message - * - * Gets the error message associated with a particular field - * - * @access public - * @param string the field name - * @return void - */ - function error($field = '', $prefix = '', $suffix = '') - { - if ( ! isset($this->_field_data[$field]['error']) OR $this->_field_data[$field]['error'] == '') - { - return ''; - } - - if ($prefix == '') - { - $prefix = $this->_error_prefix; - } - - if ($suffix == '') - { - $suffix = $this->_error_suffix; - } - - return $prefix.$this->_field_data[$field]['error'].$suffix; - } - - // -------------------------------------------------------------------- - - /** - * Error String - * - * Returns the error messages as a string, wrapped in the error delimiters - * - * @access public - * @param string - * @param string - * @return str - */ - function error_string($prefix = '', $suffix = '') - { - // No errrors, validation passes! - if (count($this->_error_array) === 0) - { - return ''; - } - - if ($prefix == '') - { - $prefix = $this->_error_prefix; - } - - if ($suffix == '') - { - $suffix = $this->_error_suffix; - } - - // Generate the error string - $str = ''; - foreach ($this->_error_array as $val) - { - if ($val != '') - { - $str .= $prefix.$val.$suffix."\n"; - } - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Run the Validator - * - * This function does all the work. - * - * @access public - * @return bool - */ - function run($group = '') - { - // Do we even have any data to process? Mm? - if (count($_POST) == 0) - { - return FALSE; - } - - // Does the _field_data array containing the validation rules exist? - // If not, we look to see if they were assigned via a config file - if (count($this->_field_data) == 0) - { - // No validation rules? We're done... - if (count($this->_config_rules) == 0) - { - return FALSE; - } - - // Is there a validation rule for the particular URI being accessed? - $uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group; - - if ($uri != '' AND isset($this->_config_rules[$uri])) - { - $this->set_rules($this->_config_rules[$uri]); - } - else - { - $this->set_rules($this->_config_rules); - } - - // We're we able to set the rules correctly? - if (count($this->_field_data) == 0) - { - log_message('debug', "Unable to find validation rules"); - return FALSE; - } - } - - // Load the language file containing error messages - $this->CI->lang->load('form_validation'); - - // Cycle through the rules for each field, match the - // corresponding $_POST item and test for errors - foreach ($this->_field_data as $field => $row) - { - // Fetch the data from the corresponding $_POST array and cache it in the _field_data array. - // Depending on whether the field name is an array or a string will determine where we get it from. - - if ($row['is_array'] == TRUE) - { - $this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']); - } - else - { - if (isset($_POST[$field]) AND $_POST[$field] != "") - { - $this->_field_data[$field]['postdata'] = $_POST[$field]; - } - } - - $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); - } - - // Did we end up with any errors? - $total_errors = count($this->_error_array); - - if ($total_errors > 0) - { - $this->_safe_form_data = TRUE; - } - - // Now we need to re-set the POST data with the new, processed data - $this->_reset_post_array(); - - // No errors, validation passes! - if ($total_errors == 0) - { - return TRUE; - } - - // Validation fails - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Traverse a multidimensional $_POST array index until the data is found - * - * @access private - * @param array - * @param array - * @param integer - * @return mixed - */ - function _reduce_array($array, $keys, $i = 0) - { - if (is_array($array)) - { - if (isset($keys[$i])) - { - if (isset($array[$keys[$i]])) - { - $array = $this->_reduce_array($array[$keys[$i]], $keys, ($i+1)); - } - else - { - return NULL; - } - } - else - { - return $array; - } - } - - return $array; - } - - // -------------------------------------------------------------------- - - /** - * Re-populate the _POST array with our finalized and processed data - * - * @access private - * @return null - */ - function _reset_post_array() - { - foreach ($this->_field_data as $field => $row) - { - if ( ! is_null($row['postdata'])) - { - if ($row['is_array'] == FALSE) - { - if (isset($_POST[$row['field']])) - { - $_POST[$row['field']] = $this->prep_for_form($row['postdata']); - } - } - else - { - // start with a reference - $post_ref =& $_POST; - - // before we assign values, make a reference to the right POST key - if (count($row['keys']) == 1) - { - $post_ref =& $post_ref[current($row['keys'])]; - } - else - { - foreach ($row['keys'] as $val) - { - $post_ref =& $post_ref[$val]; - } - } - - if (is_array($row['postdata'])) - { - $array = array(); - foreach ($row['postdata'] as $k => $v) - { - $array[$k] = $this->prep_for_form($v); - } - - $post_ref = $array; - } - else - { - $post_ref = $this->prep_for_form($row['postdata']); - } - } - } - } - } - - // -------------------------------------------------------------------- - - /** - * Executes the Validation routines - * - * @access private - * @param array - * @param array - * @param mixed - * @param integer - * @return mixed - */ - function _execute($row, $rules, $postdata = NULL, $cycles = 0) - { - // If the $_POST data is an array we will run a recursive call - if (is_array($postdata)) - { - foreach ($postdata as $key => $val) - { - $this->_execute($row, $rules, $val, $cycles); - $cycles++; - } - - return; - } - - // -------------------------------------------------------------------- - - // If the field is blank, but NOT required, no further tests are necessary - $callback = FALSE; - if ( ! in_array('required', $rules) AND is_null($postdata)) - { - // Before we bail out, does the rule contain a callback? - if (preg_match("/(callback_\w+)/", implode(' ', $rules), $match)) - { - $callback = TRUE; - $rules = (array('1' => $match[1])); - } - else - { - return; - } - } - - // -------------------------------------------------------------------- - - // Isset Test. Typically this rule will only apply to checkboxes. - if (is_null($postdata) AND $callback == FALSE) - { - if (in_array('isset', $rules, TRUE) OR in_array('required', $rules)) - { - // Set the message type - $type = (in_array('required', $rules)) ? 'required' : 'isset'; - - if ( ! isset($this->_error_messages[$type])) - { - if (FALSE === ($line = $this->CI->lang->line($type))) - { - $line = 'The field was not set'; - } - } - else - { - $line = $this->_error_messages[$type]; - } - - // Build the error message - $message = sprintf($line, $this->_translate_fieldname($row['label'])); - - // Save the error message - $this->_field_data[$row['field']]['error'] = $message; - - if ( ! isset($this->_error_array[$row['field']])) - { - $this->_error_array[$row['field']] = $message; - } - } - - return; - } - - // -------------------------------------------------------------------- - - // Cycle through each rule and run it - foreach ($rules As $rule) - { - $_in_array = FALSE; - - // We set the $postdata variable with the current data in our master array so that - // each cycle of the loop is dealing with the processed data from the last cycle - if ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata'])) - { - // We shouldn't need this safety, but just in case there isn't an array index - // associated with this cycle we'll bail out - if ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles])) - { - continue; - } - - $postdata = $this->_field_data[$row['field']]['postdata'][$cycles]; - $_in_array = TRUE; - } - else - { - $postdata = $this->_field_data[$row['field']]['postdata']; - } - - // -------------------------------------------------------------------- - - // Is the rule a callback? - $callback = FALSE; - if (substr($rule, 0, 9) == 'callback_') - { - $rule = substr($rule, 9); - $callback = TRUE; - } - - // Strip the parameter (if exists) from the rule - // Rules can contain a parameter: max_length[5] - $param = FALSE; - if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match)) - { - $rule = $match[1]; - $param = $match[2]; - } - - // Call the function that corresponds to the rule - if ($callback === TRUE) - { - if ( ! method_exists($this->CI, $rule)) - { - continue; - } - - // Run the function and grab the result - $result = $this->CI->$rule($postdata, $param); - - // Re-assign the result to the master data array - if ($_in_array == TRUE) - { - $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; - } - else - { - $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; - } - - // If the field isn't required and we just processed a callback we'll move on... - if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE) - { - continue; - } - } - else - { - if ( ! method_exists($this, $rule)) - { - // If our own wrapper function doesn't exist we see if a native PHP function does. - // Users can use any native PHP function call that has one param. - if (function_exists($rule)) - { - $result = $rule($postdata); - - if ($_in_array == TRUE) - { - $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; - } - else - { - $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; - } - } - - continue; - } - - $result = $this->$rule($postdata, $param); - - if ($_in_array == TRUE) - { - $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; - } - else - { - $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; - } - } - - // Did the rule test negatively? If so, grab the error. - if ($result === FALSE) - { - if ( ! isset($this->_error_messages[$rule])) - { - if (FALSE === ($line = $this->CI->lang->line($rule))) - { - $line = 'Unable to access an error message corresponding to your field name.'; - } - } - else - { - $line = $this->_error_messages[$rule]; - } - - // Is the parameter we are inserting into the error message the name - // of another field? If so we need to grab its "field label" - if (isset($this->_field_data[$param]) AND isset($this->_field_data[$param]['label'])) - { - $param = $this->_field_data[$param]['label']; - } - - // Build the error message - $message = sprintf($line, $this->_translate_fieldname($row['label']), $param); - - // Save the error message - $this->_field_data[$row['field']]['error'] = $message; - - if ( ! isset($this->_error_array[$row['field']])) - { - $this->_error_array[$row['field']] = $message; - } - - return; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Translate a field name - * - * @access private - * @param string the field name - * @return string - */ - function _translate_fieldname($fieldname) - { - // Do we need to translate the field name? - // We look for the prefix lang: to determine this - if (substr($fieldname, 0, 5) == 'lang:') - { - // Grab the variable - $line = substr($fieldname, 5); - - // Were we able to translate the field name? If not we use $line - if (FALSE === ($fieldname = $this->CI->lang->line($line))) - { - return $line; - } - } - - return $fieldname; - } - - // -------------------------------------------------------------------- - - /** - * Get the value from a form - * - * Permits you to repopulate a form field with the value it was submitted - * with, or, if that value doesn't exist, with the default - * - * @access public - * @param string the field name - * @param string - * @return void - */ - function set_value($field = '', $default = '') - { - if ( ! isset($this->_field_data[$field])) - { - return $default; - } - - return $this->_field_data[$field]['postdata']; - } - - // -------------------------------------------------------------------- - - /** - * Set Select - * - * Enables pull-down lists to be set to the value the user - * selected in the event of an error - * - * @access public - * @param string - * @param string - * @return string - */ - function set_select($field = '', $value = '', $default = FALSE) - { - if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) - { - if ($default === TRUE AND count($this->_field_data) === 0) - { - return ' selected="selected"'; - } - return ''; - } - - $field = $this->_field_data[$field]['postdata']; - - if (is_array($field)) - { - if ( ! in_array($value, $field)) - { - return ''; - } - } - else - { - if (($field == '' OR $value == '') OR ($field != $value)) - { - return ''; - } - } - - return ' selected="selected"'; - } - - // -------------------------------------------------------------------- - - /** - * Set Radio - * - * Enables radio buttons to be set to the value the user - * selected in the event of an error - * - * @access public - * @param string - * @param string - * @return string - */ - function set_radio($field = '', $value = '', $default = FALSE) - { - if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) - { - if ($default === TRUE AND count($this->_field_data) === 0) - { - return ' checked="checked"'; - } - return ''; - } - - $field = $this->_field_data[$field]['postdata']; - - if (is_array($field)) - { - if ( ! in_array($value, $field)) - { - return ''; - } - } - else - { - if (($field == '' OR $value == '') OR ($field != $value)) - { - return ''; - } - } - - return ' checked="checked"'; - } - - // -------------------------------------------------------------------- - - /** - * Set Checkbox - * - * Enables checkboxes to be set to the value the user - * selected in the event of an error - * - * @access public - * @param string - * @param string - * @return string - */ - function set_checkbox($field = '', $value = '', $default = FALSE) - { - if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) - { - if ($default === TRUE AND count($this->_field_data) === 0) - { - return ' checked="checked"'; - } - return ''; - } - - $field = $this->_field_data[$field]['postdata']; - - if (is_array($field)) - { - if ( ! in_array($value, $field)) - { - return ''; - } - } - else - { - if (($field == '' OR $value == '') OR ($field != $value)) - { - return ''; - } - } - - return ' checked="checked"'; - } - - // -------------------------------------------------------------------- - - /** - * Required - * - * @access public - * @param string - * @return bool - */ - function required($str) - { - if ( ! is_array($str)) - { - return (trim($str) == '') ? FALSE : TRUE; - } - else - { - return ( ! empty($str)); - } - } - - // -------------------------------------------------------------------- - - /** - * Match one field to another - * - * @access public - * @param string - * @param field - * @return bool - */ - function matches($str, $field) - { - if ( ! isset($_POST[$field])) - { - return FALSE; - } - - $field = $_POST[$field]; - - return ($str !== $field) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Minimum Length - * - * @access public - * @param string - * @param value - * @return bool - */ - function min_length($str, $val) - { - if (preg_match("/[^0-9]/", $val)) - { - return FALSE; - } - - if (function_exists('mb_strlen')) - { - return (mb_strlen($str) < $val) ? FALSE : TRUE; - } - - return (strlen($str) < $val) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Max Length - * - * @access public - * @param string - * @param value - * @return bool - */ - function max_length($str, $val) - { - if (preg_match("/[^0-9]/", $val)) - { - return FALSE; - } - - if (function_exists('mb_strlen')) - { - return (mb_strlen($str) > $val) ? FALSE : TRUE; - } - - return (strlen($str) > $val) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Exact Length - * - * @access public - * @param string - * @param value - * @return bool - */ - function exact_length($str, $val) - { - if (preg_match("/[^0-9]/", $val)) - { - return FALSE; - } - - if (function_exists('mb_strlen')) - { - return (mb_strlen($str) != $val) ? FALSE : TRUE; - } - - return (strlen($str) != $val) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Valid Email - * - * @access public - * @param string - * @return bool - */ - function valid_email($str) - { - return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Valid Emails - * - * @access public - * @param string - * @return bool - */ - function valid_emails($str) - { - if (strpos($str, ',') === FALSE) - { - return $this->valid_email(trim($str)); - } - - foreach(explode(',', $str) as $email) - { - if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE) - { - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Validate IP Address - * - * @access public - * @param string - * @return string - */ - function valid_ip($ip) - { - return $this->CI->input->valid_ip($ip); - } - - // -------------------------------------------------------------------- - - /** - * Alpha - * - * @access public - * @param string - * @return bool - */ - function alpha($str) - { - return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Alpha-numeric - * - * @access public - * @param string - * @return bool - */ - function alpha_numeric($str) - { - return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Alpha-numeric with underscores and dashes - * - * @access public - * @param string - * @return bool - */ - function alpha_dash($str) - { - return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Numeric - * - * @access public - * @param string - * @return bool - */ - function numeric($str) - { - return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str); - - } - - // -------------------------------------------------------------------- - - /** - * Is Numeric - * - * @access public - * @param string - * @return bool - */ - function is_numeric($str) - { - return ( ! is_numeric($str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Integer - * - * @access public - * @param string - * @return bool - */ - function integer($str) - { - return (bool)preg_match( '/^[\-+]?[0-9]+$/', $str); - } - - // -------------------------------------------------------------------- - - /** - * Is a Natural number (0,1,2,3, etc.) - * - * @access public - * @param string - * @return bool - */ - function is_natural($str) - { - return (bool)preg_match( '/^[0-9]+$/', $str); - } - - // -------------------------------------------------------------------- - - /** - * Is a Natural number, but not a zero (1,2,3, etc.) - * - * @access public - * @param string - * @return bool - */ - function is_natural_no_zero($str) - { - if ( ! preg_match( '/^[0-9]+$/', $str)) - { - return FALSE; - } - - if ($str == 0) - { - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Valid Base64 - * - * Tests a string for characters outside of the Base64 alphabet - * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045 - * - * @access public - * @param string - * @return bool - */ - function valid_base64($str) - { - return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); - } - - // -------------------------------------------------------------------- - - /** - * Prep data for form - * - * This function allows HTML to be safely shown in a form. - * Special characters are converted. - * - * @access public - * @param string - * @return string - */ - function prep_for_form($data = '') - { - if (is_array($data)) - { - foreach ($data as $key => $val) - { - $data[$key] = $this->prep_for_form($val); - } - - return $data; - } - - if ($this->_safe_form_data == FALSE OR $data === '') - { - return $data; - } - - return str_replace(array("'", '"', '<', '>'), array("'", """, '<', '>'), stripslashes($data)); - } - - // -------------------------------------------------------------------- - - /** - * Prep URL - * - * @access public - * @param string - * @return string - */ - function prep_url($str = '') - { - if ($str == 'http://' OR $str == '') - { - return ''; - } - - if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://') - { - $str = 'http://'.$str; - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Strip Image Tags - * - * @access public - * @param string - * @return string - */ - function strip_image_tags($str) - { - return $this->CI->input->strip_image_tags($str); - } - - // -------------------------------------------------------------------- - - /** - * XSS Clean - * - * @access public - * @param string - * @return string - */ - function xss_clean($str) - { - return $this->CI->input->xss_clean($str); - } - - // -------------------------------------------------------------------- - - /** - * Convert PHP tags to entities - * - * @access public - * @param string - * @return string - */ - function encode_php_tags($str) - { - return str_replace(array(''), array('<?php', '<?PHP', '<?', '?>'), $str); - } - -} -// END Form Validation Class - -/* End of file Form_validation.php */ +'; + var $_error_suffix = '

      '; + var $error_string = ''; + var $_safe_form_data = FALSE; + + + /** + * Constructor + * + */ + function CI_Form_validation($rules = array()) + { + $this->CI =& get_instance(); + + // Validation rules can be stored in a config file. + $this->_config_rules = $rules; + + // Automatically load the form helper + $this->CI->load->helper('form'); + + // Set the character encoding in MB. + if (function_exists('mb_internal_encoding')) + { + mb_internal_encoding($this->CI->config->item('charset')); + } + + log_message('debug', "Form Validation Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Set Rules + * + * This function takes an array of field names and validation + * rules as input, validates the info, and stores it + * + * @access public + * @param mixed + * @param string + * @return void + */ + function set_rules($field, $label = '', $rules = '') + { + // No reason to set rules if we have no POST data + if (count($_POST) == 0) + { + return; + } + + // If an array was passed via the first parameter instead of indidual string + // values we cycle through it and recursively call this function. + if (is_array($field)) + { + foreach ($field as $row) + { + // Houston, we have a problem... + if ( ! isset($row['field']) OR ! isset($row['rules'])) + { + continue; + } + + // If the field label wasn't passed we use the field name + $label = ( ! isset($row['label'])) ? $row['field'] : $row['label']; + + // Here we go! + $this->set_rules($row['field'], $label, $row['rules']); + } + return; + } + + // No fields? Nothing to do... + if ( ! is_string($field) OR ! is_string($rules) OR $field == '') + { + return; + } + + // If the field label wasn't passed we use the field name + $label = ($label == '') ? $field : $label; + + // Is the field name an array? We test for the existence of a bracket "[" in + // the field name to determine this. If it is an array, we break it apart + // into its components so that we can fetch the corresponding POST data later + if (strpos($field, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $field, $matches)) + { + // Note: Due to a bug in current() that affects some versions + // of PHP we can not pass function call directly into it + $x = explode('[', $field); + $indexes[] = current($x); + + for ($i = 0; $i < count($matches['0']); $i++) + { + if ($matches['1'][$i] != '') + { + $indexes[] = $matches['1'][$i]; + } + } + + $is_array = TRUE; + } + else + { + $indexes = array(); + $is_array = FALSE; + } + + // Build our master array + $this->_field_data[$field] = array( + 'field' => $field, + 'label' => $label, + 'rules' => $rules, + 'is_array' => $is_array, + 'keys' => $indexes, + 'postdata' => NULL, + 'error' => '' + ); + } + + // -------------------------------------------------------------------- + + /** + * Set Error Message + * + * Lets users set their own error messages on the fly. Note: The key + * name has to match the function name that it corresponds to. + * + * @access public + * @param string + * @param string + * @return string + */ + function set_message($lang, $val = '') + { + if ( ! is_array($lang)) + { + $lang = array($lang => $val); + } + + $this->_error_messages = array_merge($this->_error_messages, $lang); + } + + // -------------------------------------------------------------------- + + /** + * Set The Error Delimiter + * + * Permits a prefix/suffix to be added to each error message + * + * @access public + * @param string + * @param string + * @return void + */ + function set_error_delimiters($prefix = '

      ', $suffix = '

      ') + { + $this->_error_prefix = $prefix; + $this->_error_suffix = $suffix; + } + + // -------------------------------------------------------------------- + + /** + * Get Error Message + * + * Gets the error message associated with a particular field + * + * @access public + * @param string the field name + * @return void + */ + function error($field = '', $prefix = '', $suffix = '') + { + if ( ! isset($this->_field_data[$field]['error']) OR $this->_field_data[$field]['error'] == '') + { + return ''; + } + + if ($prefix == '') + { + $prefix = $this->_error_prefix; + } + + if ($suffix == '') + { + $suffix = $this->_error_suffix; + } + + return $prefix.$this->_field_data[$field]['error'].$suffix; + } + + // -------------------------------------------------------------------- + + /** + * Error String + * + * Returns the error messages as a string, wrapped in the error delimiters + * + * @access public + * @param string + * @param string + * @return str + */ + function error_string($prefix = '', $suffix = '') + { + // No errrors, validation passes! + if (count($this->_error_array) === 0) + { + return ''; + } + + if ($prefix == '') + { + $prefix = $this->_error_prefix; + } + + if ($suffix == '') + { + $suffix = $this->_error_suffix; + } + + // Generate the error string + $str = ''; + foreach ($this->_error_array as $val) + { + if ($val != '') + { + $str .= $prefix.$val.$suffix."\n"; + } + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Run the Validator + * + * This function does all the work. + * + * @access public + * @return bool + */ + function run($group = '') + { + // Do we even have any data to process? Mm? + if (count($_POST) == 0) + { + return FALSE; + } + + // Does the _field_data array containing the validation rules exist? + // If not, we look to see if they were assigned via a config file + if (count($this->_field_data) == 0) + { + // No validation rules? We're done... + if (count($this->_config_rules) == 0) + { + return FALSE; + } + + // Is there a validation rule for the particular URI being accessed? + $uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group; + + if ($uri != '' AND isset($this->_config_rules[$uri])) + { + $this->set_rules($this->_config_rules[$uri]); + } + else + { + $this->set_rules($this->_config_rules); + } + + // We're we able to set the rules correctly? + if (count($this->_field_data) == 0) + { + log_message('debug', "Unable to find validation rules"); + return FALSE; + } + } + + // Cycle through the rules for each field, match the + // corresponding $_POST item and test for errors + foreach ($this->_field_data as $field => $row) + { + // Fetch the data from the corresponding $_POST array and cache it in the _field_data array. + // Depending on whether the field name is an array or a string will determine where we get it from. + + if ($row['is_array'] == TRUE) + { + $this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']); + } + else + { + if (isset($_POST[$field]) AND $_POST[$field] != "") + { + $this->_field_data[$field]['postdata'] = $_POST[$field]; + } + } + + $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); + } + + // Did we end up with any errors? + $total_errors = count($this->_error_array); + + if ($total_errors > 0) + { + $this->_safe_form_data = TRUE; + } + + // Now we need to re-set the POST data with the new, processed data + $this->_reset_post_array(); + + // No errors, validation passes! + if ($total_errors == 0) + { + return TRUE; + } + + // Validation fails + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Traverse a multidimensional $_POST array index until the data is found + * + * @access private + * @param array + * @param array + * @param integer + * @return mixed + */ + function _reduce_array($array, $keys, $i = 0) + { + if (is_array($array)) + { + if (isset($keys[$i])) + { + if (isset($array[$keys[$i]])) + { + $array = $this->_reduce_array($array[$keys[$i]], $keys, ($i+1)); + } + else + { + return NULL; + } + } + else + { + return $array; + } + } + + return $array; + } + + // -------------------------------------------------------------------- + + /** + * Re-populate the _POST array with our finalized and processed data + * + * @access private + * @return null + */ + function _reset_post_array() + { + foreach ($this->_field_data as $field => $row) + { + if ( ! is_null($row['postdata'])) + { + if ($row['is_array'] == FALSE) + { + if (isset($_POST[$row['field']])) + { + $_POST[$row['field']] = $this->prep_for_form($row['postdata']); + } + } + else + { + // start with a reference + $post_ref =& $_POST; + + // before we assign values, make a reference to the right POST key + if (count($row['keys']) == 1) + { + $post_ref =& $post_ref[current($row['keys'])]; + } + else + { + foreach ($row['keys'] as $val) + { + $post_ref =& $post_ref[$val]; + } + } + + if (is_array($row['postdata'])) + { + $array = array(); + foreach ($row['postdata'] as $k => $v) + { + $array[$k] = $this->prep_for_form($v); + } + + $post_ref = $array; + } + else + { + $post_ref = $this->prep_for_form($row['postdata']); + } + } + } + } + } + + // -------------------------------------------------------------------- + + /** + * Executes the Validation routines + * + * @access private + * @param array + * @param array + * @param mixed + * @param integer + * @return mixed + */ + function _execute($row, $rules, $postdata = NULL, $cycles = 0) + { + // If the $_POST data is an array we will run a recursive call + if (is_array($postdata)) + { + foreach ($postdata as $key => $val) + { + $this->_execute($row, $rules, $val, $cycles); + $cycles++; + } + + return; + } + + // -------------------------------------------------------------------- + + // If the field is blank, but NOT required, no further tests are necessary + $callback = FALSE; + if ( ! in_array('required', $rules) AND is_null($postdata)) + { + // Before we bail out, does the rule contain a callback? + if (preg_match("/(callback_\w+)/", implode(' ', $rules), $match)) + { + $callback = TRUE; + $rules = (array('1' => $match[1])); + } + else + { + return; + } + } + + // -------------------------------------------------------------------- + + // Isset Test. Typically this rule will only apply to checkboxes. + if (is_null($postdata) AND $callback == FALSE) + { + if (in_array('isset', $rules, TRUE) OR in_array('required', $rules)) + { + // Set the message type + $type = (in_array('required', $rules)) ? 'required' : 'isset'; + + if ( ! isset($this->_error_messages[$type])) + { + if (FALSE === ($line = T_($type))) + { + $line = 'The field was not set'; + } + } + else + { + $line = $this->_error_messages[$type]; + } + + // Build the error message + $message = sprintf($line, $this->_translate_fieldname($row['label'])); + + // Save the error message + $this->_field_data[$row['field']]['error'] = $message; + + if ( ! isset($this->_error_array[$row['field']])) + { + $this->_error_array[$row['field']] = $message; + } + } + + return; + } + + // -------------------------------------------------------------------- + + // Cycle through each rule and run it + foreach ($rules As $rule) + { + $_in_array = FALSE; + + // We set the $postdata variable with the current data in our master array so that + // each cycle of the loop is dealing with the processed data from the last cycle + if ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata'])) + { + // We shouldn't need this safety, but just in case there isn't an array index + // associated with this cycle we'll bail out + if ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles])) + { + continue; + } + + $postdata = $this->_field_data[$row['field']]['postdata'][$cycles]; + $_in_array = TRUE; + } + else + { + $postdata = $this->_field_data[$row['field']]['postdata']; + } + + // -------------------------------------------------------------------- + + // Is the rule a callback? + $callback = FALSE; + if (substr($rule, 0, 9) == 'callback_') + { + $rule = substr($rule, 9); + $callback = TRUE; + } + + // Strip the parameter (if exists) from the rule + // Rules can contain a parameter: max_length[5] + $param = FALSE; + if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match)) + { + $rule = $match[1]; + $param = $match[2]; + } + + // Call the function that corresponds to the rule + if ($callback === TRUE) + { + if ( ! method_exists($this->CI, $rule)) + { + continue; + } + + // Run the function and grab the result + $result = $this->CI->$rule($postdata, $param); + + // Re-assign the result to the master data array + if ($_in_array == TRUE) + { + $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; + } + else + { + $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; + } + + // If the field isn't required and we just processed a callback we'll move on... + if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE) + { + continue; + } + } + else + { + if ( ! method_exists($this, $rule)) + { + // If our own wrapper function doesn't exist we see if a native PHP function does. + // Users can use any native PHP function call that has one param. + if (function_exists($rule)) + { + $result = $rule($postdata); + + if ($_in_array == TRUE) + { + $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; + } + else + { + $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; + } + } + + continue; + } + + $result = $this->$rule($postdata, $param); + + if ($_in_array == TRUE) + { + $this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result; + } + else + { + $this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result; + } + } + + // Did the rule test negatively? If so, grab the error. + if ($result === FALSE) + { + if ( ! isset($this->_error_messages[$rule])) + { + if (FALSE === ($line = T_($rule))) + { + $line = 'Unable to access an error message corresponding to your field name.'; + } + } + else + { + $line = $this->_error_messages[$rule]; + } + + // Is the parameter we are inserting into the error message the name + // of another field? If so we need to grab its "field label" + if (isset($this->_field_data[$param]) AND isset($this->_field_data[$param]['label'])) + { + $param = $this->_field_data[$param]['label']; + } + + // Build the error message + $message = sprintf($line, $this->_translate_fieldname($row['label']), $param); + + // Save the error message + $this->_field_data[$row['field']]['error'] = $message; + + if ( ! isset($this->_error_array[$row['field']])) + { + $this->_error_array[$row['field']] = $message; + } + + return; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Translate a field name + * + * @access private + * @param string the field name + * @return string + */ + function _translate_fieldname($fieldname) + { + // Do we need to translate the field name? + // We look for the prefix lang: to determine this + if (substr($fieldname, 0, 5) == 'lang:') + { + // Grab the variable + $line = substr($fieldname, 5); + + // Were we able to translate the field name? If not we use $line + if (FALSE === ($fieldname = T_($line))) + { + return $line; + } + } + + return $fieldname; + } + + // -------------------------------------------------------------------- + + /** + * Get the value from a form + * + * Permits you to repopulate a form field with the value it was submitted + * with, or, if that value doesn't exist, with the default + * + * @access public + * @param string the field name + * @param string + * @return void + */ + function set_value($field = '', $default = '') + { + if ( ! isset($this->_field_data[$field])) + { + return $default; + } + + return $this->_field_data[$field]['postdata']; + } + + // -------------------------------------------------------------------- + + /** + * Set Select + * + * Enables pull-down lists to be set to the value the user + * selected in the event of an error + * + * @access public + * @param string + * @param string + * @return string + */ + function set_select($field = '', $value = '', $default = FALSE) + { + if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) + { + if ($default === TRUE AND count($this->_field_data) === 0) + { + return ' selected="selected"'; + } + return ''; + } + + $field = $this->_field_data[$field]['postdata']; + + if (is_array($field)) + { + if ( ! in_array($value, $field)) + { + return ''; + } + } + else + { + if (($field == '' OR $value == '') OR ($field != $value)) + { + return ''; + } + } + + return ' selected="selected"'; + } + + // -------------------------------------------------------------------- + + /** + * Set Radio + * + * Enables radio buttons to be set to the value the user + * selected in the event of an error + * + * @access public + * @param string + * @param string + * @return string + */ + function set_radio($field = '', $value = '', $default = FALSE) + { + if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) + { + if ($default === TRUE AND count($this->_field_data) === 0) + { + return ' checked="checked"'; + } + return ''; + } + + $field = $this->_field_data[$field]['postdata']; + + if (is_array($field)) + { + if ( ! in_array($value, $field)) + { + return ''; + } + } + else + { + if (($field == '' OR $value == '') OR ($field != $value)) + { + return ''; + } + } + + return ' checked="checked"'; + } + + // -------------------------------------------------------------------- + + /** + * Set Checkbox + * + * Enables checkboxes to be set to the value the user + * selected in the event of an error + * + * @access public + * @param string + * @param string + * @return string + */ + function set_checkbox($field = '', $value = '', $default = FALSE) + { + if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])) + { + if ($default === TRUE AND count($this->_field_data) === 0) + { + return ' checked="checked"'; + } + return ''; + } + + $field = $this->_field_data[$field]['postdata']; + + if (is_array($field)) + { + if ( ! in_array($value, $field)) + { + return ''; + } + } + else + { + if (($field == '' OR $value == '') OR ($field != $value)) + { + return ''; + } + } + + return ' checked="checked"'; + } + + // -------------------------------------------------------------------- + + /** + * Required + * + * @access public + * @param string + * @return bool + */ + function required($str) + { + if ( ! is_array($str)) + { + return (trim($str) == '') ? FALSE : TRUE; + } + else + { + return ( ! empty($str)); + } + } + + // -------------------------------------------------------------------- + + /** + * Match one field to another + * + * @access public + * @param string + * @param field + * @return bool + */ + function matches($str, $field) + { + if ( ! isset($_POST[$field])) + { + return FALSE; + } + + $field = $_POST[$field]; + + return ($str !== $field) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Minimum Length + * + * @access public + * @param string + * @param value + * @return bool + */ + function min_length($str, $val) + { + if (preg_match("/[^0-9]/", $val)) + { + return FALSE; + } + + if (function_exists('mb_strlen')) + { + return (mb_strlen($str) < $val) ? FALSE : TRUE; + } + + return (strlen($str) < $val) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Max Length + * + * @access public + * @param string + * @param value + * @return bool + */ + function max_length($str, $val) + { + if (preg_match("/[^0-9]/", $val)) + { + return FALSE; + } + + if (function_exists('mb_strlen')) + { + return (mb_strlen($str) > $val) ? FALSE : TRUE; + } + + return (strlen($str) > $val) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Exact Length + * + * @access public + * @param string + * @param value + * @return bool + */ + function exact_length($str, $val) + { + if (preg_match("/[^0-9]/", $val)) + { + return FALSE; + } + + if (function_exists('mb_strlen')) + { + return (mb_strlen($str) != $val) ? FALSE : TRUE; + } + + return (strlen($str) != $val) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Valid Email + * + * @access public + * @param string + * @return bool + */ + function valid_email($str) + { + return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Valid Emails + * + * @access public + * @param string + * @return bool + */ + function valid_emails($str) + { + if (strpos($str, ',') === FALSE) + { + return $this->valid_email(trim($str)); + } + + foreach(explode(',', $str) as $email) + { + if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE) + { + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Validate IP Address + * + * @access public + * @param string + * @return string + */ + function valid_ip($ip) + { + return $this->CI->input->valid_ip($ip); + } + + // -------------------------------------------------------------------- + + /** + * Alpha + * + * @access public + * @param string + * @return bool + */ + function alpha($str) + { + return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Alpha-numeric + * + * @access public + * @param string + * @return bool + */ + function alpha_numeric($str) + { + return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Alpha-numeric with underscores and dashes + * + * @access public + * @param string + * @return bool + */ + function alpha_dash($str) + { + return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Numeric + * + * @access public + * @param string + * @return bool + */ + function numeric($str) + { + return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str); + + } + + // -------------------------------------------------------------------- + + /** + * Is Numeric + * + * @access public + * @param string + * @return bool + */ + function is_numeric($str) + { + return ( ! is_numeric($str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Integer + * + * @access public + * @param string + * @return bool + */ + function integer($str) + { + return (bool)preg_match( '/^[\-+]?[0-9]+$/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Is a Natural number (0,1,2,3, etc.) + * + * @access public + * @param string + * @return bool + */ + function is_natural($str) + { + return (bool)preg_match( '/^[0-9]+$/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Is a Natural number, but not a zero (1,2,3, etc.) + * + * @access public + * @param string + * @return bool + */ + function is_natural_no_zero($str) + { + if ( ! preg_match( '/^[0-9]+$/', $str)) + { + return FALSE; + } + + if ($str == 0) + { + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Valid Base64 + * + * Tests a string for characters outside of the Base64 alphabet + * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045 + * + * @access public + * @param string + * @return bool + */ + function valid_base64($str) + { + return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Prep data for form + * + * This function allows HTML to be safely shown in a form. + * Special characters are converted. + * + * @access public + * @param string + * @return string + */ + function prep_for_form($data = '') + { + if (is_array($data)) + { + foreach ($data as $key => $val) + { + $data[$key] = $this->prep_for_form($val); + } + + return $data; + } + + if ($this->_safe_form_data == FALSE OR $data === '') + { + return $data; + } + + return str_replace(array("'", '"', '<', '>'), array("'", """, '<', '>'), stripslashes($data)); + } + + // -------------------------------------------------------------------- + + /** + * Prep URL + * + * @access public + * @param string + * @return string + */ + function prep_url($str = '') + { + if ($str == 'http://' OR $str == '') + { + return ''; + } + + if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://') + { + $str = 'http://'.$str; + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Strip Image Tags + * + * @access public + * @param string + * @return string + */ + function strip_image_tags($str) + { + return $this->CI->input->strip_image_tags($str); + } + + // -------------------------------------------------------------------- + + /** + * XSS Clean + * + * @access public + * @param string + * @return string + */ + function xss_clean($str) + { + return $this->CI->input->xss_clean($str); + } + + // -------------------------------------------------------------------- + + /** + * Convert PHP tags to entities + * + * @access public + * @param string + * @return string + */ + function encode_php_tags($str) + { + return str_replace(array(''), array('<?php', '<?PHP', '<?', '?>'), $str); + } + +} +// END Form Validation Class + +/* End of file Form_validation.php */ /* Location: ./system/libraries/Form_validation.php */ \ No newline at end of file diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index 16ad9ad..6f47265 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -1,618 +1,617 @@ - 0) - { - $this->initialize($config); - } - - log_message('debug', "FTP Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Initialize preferences - * - * @access public - * @param array - * @return void - */ - function initialize($config = array()) - { - foreach ($config as $key => $val) - { - if (isset($this->$key)) - { - $this->$key = $val; - } - } - - // Prep the hostname - $this->hostname = preg_replace('|.+?://|', '', $this->hostname); - } - - // -------------------------------------------------------------------- - - /** - * FTP Connect - * - * @access public - * @param array the connection values - * @return bool - */ - function connect($config = array()) - { - if (count($config) > 0) - { - $this->initialize($config); - } - - if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port))) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_connect'); - } - return FALSE; - } - - if ( ! $this->_login()) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_login'); - } - return FALSE; - } - - // Set passive mode if needed - if ($this->passive == TRUE) - { - ftp_pasv($this->conn_id, TRUE); - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * FTP Login - * - * @access private - * @return bool - */ - function _login() - { - return @ftp_login($this->conn_id, $this->username, $this->password); - } - - // -------------------------------------------------------------------- - - /** - * Validates the connection ID - * - * @access private - * @return bool - */ - function _is_conn() - { - if ( ! is_resource($this->conn_id)) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_no_connection'); - } - return FALSE; - } - return TRUE; - } - - // -------------------------------------------------------------------- - - - /** - * Change directory - * - * The second parameter lets us momentarily turn off debugging so that - * this function can be used to test for the existence of a folder - * without throwing an error. There's no FTP equivalent to is_dir() - * so we do it by trying to change to a particular directory. - * Internally, this parameter is only used by the "mirror" function below. - * - * @access public - * @param string - * @param bool - * @return bool - */ - function changedir($path = '', $supress_debug = FALSE) - { - if ($path == '' OR ! $this->_is_conn()) - { - return FALSE; - } - - $result = @ftp_chdir($this->conn_id, $path); - - if ($result === FALSE) - { - if ($this->debug == TRUE AND $supress_debug == FALSE) - { - $this->_error('ftp_unable_to_changedir'); - } - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Create a directory - * - * @access public - * @param string - * @return bool - */ - function mkdir($path = '', $permissions = NULL) - { - if ($path == '' OR ! $this->_is_conn()) - { - return FALSE; - } - - $result = @ftp_mkdir($this->conn_id, $path); - - if ($result === FALSE) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_makdir'); - } - return FALSE; - } - - // Set file permissions if needed - if ( ! is_null($permissions)) - { - $this->chmod($path, (int)$permissions); - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Upload a file to the server - * - * @access public - * @param string - * @param string - * @param string - * @return bool - */ - function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL) - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - if ( ! file_exists($locpath)) - { - $this->_error('ftp_no_source_file'); - return FALSE; - } - - // Set the mode if not specified - if ($mode == 'auto') - { - // Get the file extension so we can set the upload type - $ext = $this->_getext($locpath); - $mode = $this->_settype($ext); - } - - $mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY; - - $result = @ftp_put($this->conn_id, $rempath, $locpath, $mode); - - if ($result === FALSE) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_upload'); - } - return FALSE; - } - - // Set file permissions if needed - if ( ! is_null($permissions)) - { - $this->chmod($rempath, (int)$permissions); - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Rename (or move) a file - * - * @access public - * @param string - * @param string - * @param bool - * @return bool - */ - function rename($old_file, $new_file, $move = FALSE) - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - $result = @ftp_rename($this->conn_id, $old_file, $new_file); - - if ($result === FALSE) - { - if ($this->debug == TRUE) - { - $msg = ($move == FALSE) ? 'ftp_unable_to_rename' : 'ftp_unable_to_move'; - - $this->_error($msg); - } - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Move a file - * - * @access public - * @param string - * @param string - * @return bool - */ - function move($old_file, $new_file) - { - return $this->rename($old_file, $new_file, TRUE); - } - - // -------------------------------------------------------------------- - - /** - * Rename (or move) a file - * - * @access public - * @param string - * @return bool - */ - function delete_file($filepath) - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - $result = @ftp_delete($this->conn_id, $filepath); - - if ($result === FALSE) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_delete'); - } - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Delete a folder and recursively delete everything (including sub-folders) - * containted within it. - * - * @access public - * @param string - * @return bool - */ - function delete_dir($filepath) - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - // Add a trailing slash to the file path if needed - $filepath = preg_replace("/(.+?)\/*$/", "\\1/", $filepath); - - $list = $this->list_files($filepath); - - if ($list !== FALSE AND count($list) > 0) - { - foreach ($list as $item) - { - // If we can't delete the item it's probaly a folder so - // we'll recursively call delete_dir() - if ( ! @ftp_delete($this->conn_id, $item)) - { - $this->delete_dir($item); - } - } - } - - $result = @ftp_rmdir($this->conn_id, $filepath); - - if ($result === FALSE) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_delete'); - } - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Set file permissions - * - * @access public - * @param string the file path - * @param string the permissions - * @return bool - */ - function chmod($path, $perm) - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - // Permissions can only be set when running PHP 5 - if ( ! function_exists('ftp_chmod')) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_chmod'); - } - return FALSE; - } - - $result = @ftp_chmod($this->conn_id, $perm, $path); - - if ($result === FALSE) - { - if ($this->debug == TRUE) - { - $this->_error('ftp_unable_to_chmod'); - } - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * FTP List files in the specified directory - * - * @access public - * @return array - */ - function list_files($path = '.') - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - return ftp_nlist($this->conn_id, $path); - } - - // ------------------------------------------------------------------------ - - /** - * Read a directory and recreate it remotely - * - * This function recursively reads a folder and everything it contains (including - * sub-folders) and creates a mirror via FTP based on it. Whatever the directory structure - * of the original file path will be recreated on the server. - * - * @access public - * @param string path to source with trailing slash - * @param string path to destination - include the base folder with trailing slash - * @return bool - */ - function mirror($locpath, $rempath) - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - // Open the local file path - if ($fp = @opendir($locpath)) - { - // Attempt to open the remote file path. - if ( ! $this->changedir($rempath, TRUE)) - { - // If it doesn't exist we'll attempt to create the direcotory - if ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath)) - { - return FALSE; - } - } - - // Recursively read the local directory - while (FALSE !== ($file = readdir($fp))) - { - if (@is_dir($locpath.$file) && substr($file, 0, 1) != '.') - { - $this->mirror($locpath.$file."/", $rempath.$file."/"); - } - elseif (substr($file, 0, 1) != ".") - { - // Get the file extension so we can se the upload type - $ext = $this->_getext($file); - $mode = $this->_settype($ext); - - $this->upload($locpath.$file, $rempath.$file, $mode); - } - } - return TRUE; - } - - return FALSE; - } - - - // -------------------------------------------------------------------- - - /** - * Extract the file extension - * - * @access private - * @param string - * @return string - */ - function _getext($filename) - { - if (FALSE === strpos($filename, '.')) - { - return 'txt'; - } - - $x = explode('.', $filename); - return end($x); - } - - - // -------------------------------------------------------------------- - - /** - * Set the upload type - * - * @access private - * @param string - * @return string - */ - function _settype($ext) - { - $text_types = array( - 'txt', - 'text', - 'php', - 'phps', - 'php4', - 'js', - 'css', - 'htm', - 'html', - 'phtml', - 'shtml', - 'log', - 'xml' - ); - - - return (in_array($ext, $text_types)) ? 'ascii' : 'binary'; - } - - // ------------------------------------------------------------------------ - - /** - * Close the connection - * - * @access public - * @param string path to source - * @param string path to destination - * @return bool - */ - function close() - { - if ( ! $this->_is_conn()) - { - return FALSE; - } - - @ftp_close($this->conn_id); - } - - // ------------------------------------------------------------------------ - - /** - * Display error message - * - * @access private - * @param string - * @return bool - */ - function _error($line) - { - $CI =& get_instance(); - $CI->lang->load('ftp'); - show_error($CI->lang->line($line)); - } - - -} -// END FTP Class - -/* End of file Ftp.php */ + 0) + { + $this->initialize($config); + } + + log_message('debug', "FTP Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize preferences + * + * @access public + * @param array + * @return void + */ + function initialize($config = array()) + { + foreach ($config as $key => $val) + { + if (isset($this->$key)) + { + $this->$key = $val; + } + } + + // Prep the hostname + $this->hostname = preg_replace('|.+?://|', '', $this->hostname); + } + + // -------------------------------------------------------------------- + + /** + * FTP Connect + * + * @access public + * @param array the connection values + * @return bool + */ + function connect($config = array()) + { + if (count($config) > 0) + { + $this->initialize($config); + } + + if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port))) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_connect'); + } + return FALSE; + } + + if ( ! $this->_login()) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_login'); + } + return FALSE; + } + + // Set passive mode if needed + if ($this->passive == TRUE) + { + ftp_pasv($this->conn_id, TRUE); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * FTP Login + * + * @access private + * @return bool + */ + function _login() + { + return @ftp_login($this->conn_id, $this->username, $this->password); + } + + // -------------------------------------------------------------------- + + /** + * Validates the connection ID + * + * @access private + * @return bool + */ + function _is_conn() + { + if ( ! is_resource($this->conn_id)) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_no_connection'); + } + return FALSE; + } + return TRUE; + } + + // -------------------------------------------------------------------- + + + /** + * Change directory + * + * The second parameter lets us momentarily turn off debugging so that + * this function can be used to test for the existence of a folder + * without throwing an error. There's no FTP equivalent to is_dir() + * so we do it by trying to change to a particular directory. + * Internally, this parameter is only used by the "mirror" function below. + * + * @access public + * @param string + * @param bool + * @return bool + */ + function changedir($path = '', $supress_debug = FALSE) + { + if ($path == '' OR ! $this->_is_conn()) + { + return FALSE; + } + + $result = @ftp_chdir($this->conn_id, $path); + + if ($result === FALSE) + { + if ($this->debug == TRUE AND $supress_debug == FALSE) + { + $this->_error('ftp_unable_to_changedir'); + } + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Create a directory + * + * @access public + * @param string + * @return bool + */ + function mkdir($path = '', $permissions = NULL) + { + if ($path == '' OR ! $this->_is_conn()) + { + return FALSE; + } + + $result = @ftp_mkdir($this->conn_id, $path); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_makdir'); + } + return FALSE; + } + + // Set file permissions if needed + if ( ! is_null($permissions)) + { + $this->chmod($path, (int)$permissions); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Upload a file to the server + * + * @access public + * @param string + * @param string + * @param string + * @return bool + */ + function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL) + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + if ( ! file_exists($locpath)) + { + $this->_error('ftp_no_source_file'); + return FALSE; + } + + // Set the mode if not specified + if ($mode == 'auto') + { + // Get the file extension so we can set the upload type + $ext = $this->_getext($locpath); + $mode = $this->_settype($ext); + } + + $mode = ($mode == 'ascii') ? FTP_ASCII : FTP_BINARY; + + $result = @ftp_put($this->conn_id, $rempath, $locpath, $mode); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_upload'); + } + return FALSE; + } + + // Set file permissions if needed + if ( ! is_null($permissions)) + { + $this->chmod($rempath, (int)$permissions); + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Rename (or move) a file + * + * @access public + * @param string + * @param string + * @param bool + * @return bool + */ + function rename($old_file, $new_file, $move = FALSE) + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + $result = @ftp_rename($this->conn_id, $old_file, $new_file); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $msg = ($move == FALSE) ? 'ftp_unable_to_rename' : 'ftp_unable_to_move'; + + $this->_error($msg); + } + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Move a file + * + * @access public + * @param string + * @param string + * @return bool + */ + function move($old_file, $new_file) + { + return $this->rename($old_file, $new_file, TRUE); + } + + // -------------------------------------------------------------------- + + /** + * Rename (or move) a file + * + * @access public + * @param string + * @return bool + */ + function delete_file($filepath) + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + $result = @ftp_delete($this->conn_id, $filepath); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_delete'); + } + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Delete a folder and recursively delete everything (including sub-folders) + * containted within it. + * + * @access public + * @param string + * @return bool + */ + function delete_dir($filepath) + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + // Add a trailing slash to the file path if needed + $filepath = preg_replace("/(.+?)\/*$/", "\\1/", $filepath); + + $list = $this->list_files($filepath); + + if ($list !== FALSE AND count($list) > 0) + { + foreach ($list as $item) + { + // If we can't delete the item it's probaly a folder so + // we'll recursively call delete_dir() + if ( ! @ftp_delete($this->conn_id, $item)) + { + $this->delete_dir($item); + } + } + } + + $result = @ftp_rmdir($this->conn_id, $filepath); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_delete'); + } + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set file permissions + * + * @access public + * @param string the file path + * @param string the permissions + * @return bool + */ + function chmod($path, $perm) + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + // Permissions can only be set when running PHP 5 + if ( ! function_exists('ftp_chmod')) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_chmod'); + } + return FALSE; + } + + $result = @ftp_chmod($this->conn_id, $perm, $path); + + if ($result === FALSE) + { + if ($this->debug == TRUE) + { + $this->_error('ftp_unable_to_chmod'); + } + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * FTP List files in the specified directory + * + * @access public + * @return array + */ + function list_files($path = '.') + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + return ftp_nlist($this->conn_id, $path); + } + + // ------------------------------------------------------------------------ + + /** + * Read a directory and recreate it remotely + * + * This function recursively reads a folder and everything it contains (including + * sub-folders) and creates a mirror via FTP based on it. Whatever the directory structure + * of the original file path will be recreated on the server. + * + * @access public + * @param string path to source with trailing slash + * @param string path to destination - include the base folder with trailing slash + * @return bool + */ + function mirror($locpath, $rempath) + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + // Open the local file path + if ($fp = @opendir($locpath)) + { + // Attempt to open the remote file path. + if ( ! $this->changedir($rempath, TRUE)) + { + // If it doesn't exist we'll attempt to create the direcotory + if ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath)) + { + return FALSE; + } + } + + // Recursively read the local directory + while (FALSE !== ($file = readdir($fp))) + { + if (@is_dir($locpath.$file) && substr($file, 0, 1) != '.') + { + $this->mirror($locpath.$file."/", $rempath.$file."/"); + } + elseif (substr($file, 0, 1) != ".") + { + // Get the file extension so we can se the upload type + $ext = $this->_getext($file); + $mode = $this->_settype($ext); + + $this->upload($locpath.$file, $rempath.$file, $mode); + } + } + return TRUE; + } + + return FALSE; + } + + + // -------------------------------------------------------------------- + + /** + * Extract the file extension + * + * @access private + * @param string + * @return string + */ + function _getext($filename) + { + if (FALSE === strpos($filename, '.')) + { + return 'txt'; + } + + $x = explode('.', $filename); + return end($x); + } + + + // -------------------------------------------------------------------- + + /** + * Set the upload type + * + * @access private + * @param string + * @return string + */ + function _settype($ext) + { + $text_types = array( + 'txt', + 'text', + 'php', + 'phps', + 'php4', + 'js', + 'css', + 'htm', + 'html', + 'phtml', + 'shtml', + 'log', + 'xml' + ); + + + return (in_array($ext, $text_types)) ? 'ascii' : 'binary'; + } + + // ------------------------------------------------------------------------ + + /** + * Close the connection + * + * @access public + * @param string path to source + * @param string path to destination + * @return bool + */ + function close() + { + if ( ! $this->_is_conn()) + { + return FALSE; + } + + @ftp_close($this->conn_id); + } + + // ------------------------------------------------------------------------ + + /** + * Display error message + * + * @access private + * @param string + * @return bool + */ + function _error($line) + { + $CI =& get_instance(); + show_error(T_($line)); + } + + +} +// END FTP Class + +/* End of file Ftp.php */ /* Location: ./system/libraries/Ftp.php */ \ No newline at end of file diff --git a/system/libraries/Hooks.php b/system/libraries/Hooks.php index b77cf5b..00c954b 100644 --- a/system/libraries/Hooks.php +++ b/system/libraries/Hooks.php @@ -1,226 +1,226 @@ -_initialize(); - log_message('debug', "Hooks Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Initialize the Hooks Preferences - * - * @access private - * @return void - */ - function _initialize() - { - $CFG =& load_class('Config'); - - // 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. - - @include(APPPATH.'config/hooks'.EXT); - - 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 */ +_initialize(); + log_message('debug', "Hooks Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize the Hooks Preferences + * + * @access private + * @return void + */ + function _initialize() + { + $CFG =& load_class('Config'); + + // 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. + + @include(APPPATH.'config/hooks'.EXT); + + 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/libraries/Hooks.php */ \ No newline at end of file diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index 58a1628..83c6e9b 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -1,1544 +1,1543 @@ - 0) - { - $this->initialize($props); - } - - log_message('debug', "Image Lib Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Initialize image properties - * - * Resets values in case this class is used in a loop - * - * @access public - * @return void - */ - function clear() - { - $props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity'); - - foreach ($props as $val) - { - $this->$val = ''; - } - - // special consideration for master_dim - $this->master_dim = 'auto'; - } - - // -------------------------------------------------------------------- - - /** - * initialize image preferences - * - * @access public - * @param array - * @return bool - */ - function initialize($props = array()) - { - /* - * Convert array elements into class variables - */ - if (count($props) > 0) - { - foreach ($props as $key => $val) - { - $this->$key = $val; - } - } - - /* - * Is there a source image? - * - * If not, there's no reason to continue - * - */ - if ($this->source_image == '') - { - $this->set_error('imglib_source_image_required'); - return FALSE; - } - - /* - * Is getimagesize() Available? - * - * We use it to determine the image properties (width/height). - * Note: We need to figure out how to determine image - * properties using ImageMagick and NetPBM - * - */ - if ( ! function_exists('getimagesize')) - { - $this->set_error('imglib_gd_required_for_props'); - return FALSE; - } - - $this->image_library = strtolower($this->image_library); - - /* - * Set the full server path - * - * The source image may or may not contain a path. - * Either way, we'll try use realpath to generate the - * full server path in order to more reliably read it. - * - */ - if (function_exists('realpath') AND @realpath($this->source_image) !== FALSE) - { - $full_source_path = str_replace("\\", "/", realpath($this->source_image)); - } - else - { - $full_source_path = $this->source_image; - } - - $x = explode('/', $full_source_path); - $this->source_image = end($x); - $this->source_folder = str_replace($this->source_image, '', $full_source_path); - - // Set the Image Properties - if ( ! $this->get_image_properties($this->source_folder.$this->source_image)) - { - return FALSE; - } - - /* - * Assign the "new" image name/path - * - * If the user has set a "new_image" name it means - * we are making a copy of the source image. If not - * it means we are altering the original. We'll - * set the destination filename and path accordingly. - * - */ - if ($this->new_image == '') - { - $this->dest_image = $this->source_image; - $this->dest_folder = $this->source_folder; - } - else - { - if (strpos($this->new_image, '/') === FALSE) - { - $this->dest_folder = $this->source_folder; - $this->dest_image = $this->new_image; - } - else - { - if (function_exists('realpath') AND @realpath($this->new_image) !== FALSE) - { - $full_dest_path = str_replace("\\", "/", realpath($this->new_image)); - } - else - { - $full_dest_path = $this->new_image; - } - - // Is there a file name? - if ( ! preg_match("#\.(jpg|jpeg|gif|png)$#i", $full_dest_path)) - { - $this->dest_folder = $full_dest_path.'/'; - $this->dest_image = $this->source_image; - } - else - { - $x = explode('/', $full_dest_path); - $this->dest_image = end($x); - $this->dest_folder = str_replace($this->dest_image, '', $full_dest_path); - } - } - } - - /* - * Compile the finalized filenames/paths - * - * We'll create two master strings containing the - * full server path to the source image and the - * full server path to the destination image. - * We'll also split the destination image name - * so we can insert the thumbnail marker if needed. - * - */ - if ($this->create_thumb === FALSE OR $this->thumb_marker == '') - { - $this->thumb_marker = ''; - } - - $xp = $this->explode_name($this->dest_image); - - $filename = $xp['name']; - $file_ext = $xp['ext']; - - $this->full_src_path = $this->source_folder.$this->source_image; - $this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext; - - /* - * Should we maintain image proportions? - * - * When creating thumbs or copies, the target width/height - * might not be in correct proportion with the source - * image's width/height. We'll recalculate it here. - * - */ - if ($this->maintain_ratio === TRUE && ($this->width != '' AND $this->height != '')) - { - $this->image_reproportion(); - } - - /* - * Was a width and height specified? - * - * If the destination width/height was - * not submitted we will use the values - * from the actual file - * - */ - if ($this->width == '') - $this->width = $this->orig_width; - - if ($this->height == '') - $this->height = $this->orig_height; - - // Set the quality - $this->quality = trim(str_replace("%", "", $this->quality)); - - if ($this->quality == '' OR $this->quality == 0 OR ! is_numeric($this->quality)) - $this->quality = 90; - - // Set the x/y coordinates - $this->x_axis = ($this->x_axis == '' OR ! is_numeric($this->x_axis)) ? 0 : $this->x_axis; - $this->y_axis = ($this->y_axis == '' OR ! is_numeric($this->y_axis)) ? 0 : $this->y_axis; - - // Watermark-related Stuff... - if ($this->wm_font_color != '') - { - if (strlen($this->wm_font_color) == 6) - { - $this->wm_font_color = '#'.$this->wm_font_color; - } - } - - if ($this->wm_shadow_color != '') - { - if (strlen($this->wm_shadow_color) == 6) - { - $this->wm_shadow_color = '#'.$this->wm_shadow_color; - } - } - - if ($this->wm_overlay_path != '') - { - $this->wm_overlay_path = str_replace("\\", "/", realpath($this->wm_overlay_path)); - } - - if ($this->wm_shadow_color != '') - { - $this->wm_use_drop_shadow = TRUE; - } - - if ($this->wm_font_path != '') - { - $this->wm_use_truetype = TRUE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Image Resize - * - * This is a wrapper function that chooses the proper - * resize function based on the protocol specified - * - * @access public - * @return bool - */ - function resize() - { - $protocol = 'image_process_'.$this->image_library; - - if (preg_match('/gd2$/i', $protocol)) - { - $protocol = 'image_process_gd'; - } - - return $this->$protocol('resize'); - } - - // -------------------------------------------------------------------- - - /** - * Image Crop - * - * This is a wrapper function that chooses the proper - * cropping function based on the protocol specified - * - * @access public - * @return bool - */ - function crop() - { - $protocol = 'image_process_'.$this->image_library; - - if (preg_match('/gd2$/i', $protocol)) - { - $protocol = 'image_process_gd'; - } - - return $this->$protocol('crop'); - } - - // -------------------------------------------------------------------- - - /** - * Image Rotate - * - * This is a wrapper function that chooses the proper - * rotation function based on the protocol specified - * - * @access public - * @return bool - */ - function rotate() - { - // Allowed rotation values - $degs = array(90, 180, 270, 'vrt', 'hor'); - - if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs)) - { - $this->set_error('imglib_rotation_angle_required'); - return FALSE; - } - - // Reassign the width and height - if ($this->rotation_angle == 90 OR $this->rotation_angle == 270) - { - $this->width = $this->orig_height; - $this->height = $this->orig_width; - } - else - { - $this->width = $this->orig_width; - $this->height = $this->orig_height; - } - - - // Choose resizing function - if ($this->image_library == 'imagemagick' OR $this->image_library == 'netpbm') - { - $protocol = 'image_process_'.$this->image_library; - - return $this->$protocol('rotate'); - } - - if ($this->rotation_angle == 'hor' OR $this->rotation_angle == 'vrt') - { - return $this->image_mirror_gd(); - } - else - { - return $this->image_rotate_gd(); - } - } - - // -------------------------------------------------------------------- - - /** - * Image Process Using GD/GD2 - * - * This function will resize or crop - * - * @access public - * @param string - * @return bool - */ - function image_process_gd($action = 'resize') - { - $v2_override = FALSE; - - // If the target width/height match the source, AND if the new file name is not equal to the old file name - // we'll simply make a copy of the original with the new name... assuming dynamic rendering is off. - if ($this->dynamic_output === FALSE) - { - if ($this->orig_width == $this->width AND $this->orig_height == $this->height) - { - if ($this->source_image != $this->new_image) - { - if (@copy($this->full_src_path, $this->full_dst_path)) - { - @chmod($this->full_dst_path, DIR_WRITE_MODE); - } - } - - return TRUE; - } - } - - // Let's set up our values based on the action - if ($action == 'crop') - { - // Reassign the source width/height if cropping - $this->orig_width = $this->width; - $this->orig_height = $this->height; - - // GD 2.0 has a cropping bug so we'll test for it - if ($this->gd_version() !== FALSE) - { - $gd_version = str_replace('0', '', $this->gd_version()); - $v2_override = ($gd_version == 2) ? TRUE : FALSE; - } - } - else - { - // If resizing the x/y axis must be zero - $this->x_axis = 0; - $this->y_axis = 0; - } - - // Create the image handle - if ( ! ($src_img = $this->image_create_gd())) - { - return FALSE; - } - - // Create The Image - // - // old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater" - // it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment - // below should that ever prove inaccurate. - // - // if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE) - if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor')) - { - $create = 'imagecreatetruecolor'; - $copy = 'imagecopyresampled'; - } - else - { - $create = 'imagecreate'; - $copy = 'imagecopyresized'; - } - - $dst_img = $create($this->width, $this->height); - $copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height); - - // Show the image - if ($this->dynamic_output == TRUE) - { - $this->image_display_gd($dst_img); - } - else - { - // Or save it - if ( ! $this->image_save_gd($dst_img)) - { - return FALSE; - } - } - - // Kill the file handles - imagedestroy($dst_img); - imagedestroy($src_img); - - // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Image Process Using ImageMagick - * - * This function will resize, crop or rotate - * - * @access public - * @param string - * @return bool - */ - function image_process_imagemagick($action = 'resize') - { - // Do we have a vaild library path? - if ($this->library_path == '') - { - $this->set_error('imglib_libpath_invalid'); - return FALSE; - } - - if ( ! preg_match("/convert$/i", $this->library_path)) - { - $this->library_path = rtrim($this->library_path, '/').'/'; - - $this->library_path .= 'convert'; - } - - // Execute the command - $cmd = $this->library_path." -quality ".$this->quality; - - if ($action == 'crop') - { - $cmd .= " -crop ".$this->width."x".$this->height."+".$this->x_axis."+".$this->y_axis." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1"; - } - elseif ($action == 'rotate') - { - switch ($this->rotation_angle) - { - case 'hor' : $angle = '-flop'; - break; - case 'vrt' : $angle = '-flip'; - break; - default : $angle = '-rotate '.$this->rotation_angle; - break; - } - - $cmd .= " ".$angle." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1"; - } - else // Resize - { - $cmd .= " -resize ".$this->width."x".$this->height." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1"; - } - - $retval = 1; - - @exec($cmd, $output, $retval); - - // Did it work? - if ($retval > 0) - { - $this->set_error('imglib_image_process_failed'); - return FALSE; - } - - // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Image Process Using NetPBM - * - * This function will resize, crop or rotate - * - * @access public - * @param string - * @return bool - */ - function image_process_netpbm($action = 'resize') - { - if ($this->library_path == '') - { - $this->set_error('imglib_libpath_invalid'); - return FALSE; - } - - // Build the resizing command - switch ($this->image_type) - { - case 1 : - $cmd_in = 'giftopnm'; - $cmd_out = 'ppmtogif'; - break; - case 2 : - $cmd_in = 'jpegtopnm'; - $cmd_out = 'ppmtojpeg'; - break; - case 3 : - $cmd_in = 'pngtopnm'; - $cmd_out = 'ppmtopng'; - break; - } - - if ($action == 'crop') - { - $cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height; - } - elseif ($action == 'rotate') - { - switch ($this->rotation_angle) - { - case 90 : $angle = 'r270'; - break; - case 180 : $angle = 'r180'; - break; - case 270 : $angle = 'r90'; - break; - case 'vrt' : $angle = 'tb'; - break; - case 'hor' : $angle = 'lr'; - break; - } - - $cmd_inner = 'pnmflip -'.$angle.' '; - } - else // Resize - { - $cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height; - } - - $cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp'; - - $retval = 1; - - @exec($cmd, $output, $retval); - - // Did it work? - if ($retval > 0) - { - $this->set_error('imglib_image_process_failed'); - return FALSE; - } - - // With NetPBM we have to create a temporary image. - // If you try manipulating the original it fails so - // we have to rename the temp file. - copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path); - unlink ($this->dest_folder.'netpbm.tmp'); - @chmod($this->full_dst_path, DIR_WRITE_MODE); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Image Rotate Using GD - * - * @access public - * @return bool - */ - function image_rotate_gd() - { - // Is Image Rotation Supported? - // this function is only supported as of PHP 4.3 - if ( ! function_exists('imagerotate')) - { - $this->set_error('imglib_rotate_unsupported'); - return FALSE; - } - - // Create the image handle - if ( ! ($src_img = $this->image_create_gd())) - { - return FALSE; - } - - // Set the background color - // This won't work with transparent PNG files so we are - // going to have to figure out how to determine the color - // of the alpha channel in a future release. - - $white = imagecolorallocate($src_img, 255, 255, 255); - - // Rotate it! - $dst_img = imagerotate($src_img, $this->rotation_angle, $white); - - // Save the Image - if ($this->dynamic_output == TRUE) - { - $this->image_display_gd($dst_img); - } - else - { - // Or save it - if ( ! $this->image_save_gd($dst_img)) - { - return FALSE; - } - } - - // Kill the file handles - imagedestroy($dst_img); - imagedestroy($src_img); - - // Set the file to 777 - - @chmod($this->full_dst_path, DIR_WRITE_MODE); - - return true; - } - - // -------------------------------------------------------------------- - - /** - * Create Mirror Image using GD - * - * This function will flip horizontal or vertical - * - * @access public - * @return bool - */ - function image_mirror_gd() - { - if ( ! $src_img = $this->image_create_gd()) - { - return FALSE; - } - - $width = $this->orig_width; - $height = $this->orig_height; - - if ($this->rotation_angle == 'hor') - { - for ($i = 0; $i < $height; $i++) - { - $left = 0; - $right = $width-1; - - while ($left < $right) - { - $cl = imagecolorat($src_img, $left, $i); - $cr = imagecolorat($src_img, $right, $i); - - imagesetpixel($src_img, $left, $i, $cr); - imagesetpixel($src_img, $right, $i, $cl); - - $left++; - $right--; - } - } - } - else - { - for ($i = 0; $i < $width; $i++) - { - $top = 0; - $bot = $height-1; - - while ($top < $bot) - { - $ct = imagecolorat($src_img, $i, $top); - $cb = imagecolorat($src_img, $i, $bot); - - imagesetpixel($src_img, $i, $top, $cb); - imagesetpixel($src_img, $i, $bot, $ct); - - $top++; - $bot--; - } - } - } - - // Show the image - if ($this->dynamic_output == TRUE) - { - $this->image_display_gd($src_img); - } - else - { - // Or save it - if ( ! $this->image_save_gd($src_img)) - { - return FALSE; - } - } - - // Kill the file handles - imagedestroy($src_img); - - // Set the file to 777 - @chmod($this->full_dst_path, DIR_WRITE_MODE); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Image Watermark - * - * This is a wrapper function that chooses the type - * of watermarking based on the specified preference. - * - * @access public - * @param string - * @return bool - */ - function watermark() - { - if ($this->wm_type == 'overlay') - { - return $this->overlay_watermark(); - } - else - { - return $this->text_watermark(); - } - } - - // -------------------------------------------------------------------- - - /** - * Watermark - Graphic Version - * - * @access public - * @return bool - */ - function overlay_watermark() - { - if ( ! function_exists('imagecolortransparent')) - { - $this->set_error('imglib_gd_required'); - return FALSE; - } - - // Fetch source image properties - $this->get_image_properties(); - - // Fetch watermark image properties - $props = $this->get_image_properties($this->wm_overlay_path, TRUE); - $wm_img_type = $props['image_type']; - $wm_width = $props['width']; - $wm_height = $props['height']; - - // Create two image resources - $wm_img = $this->image_create_gd($this->wm_overlay_path, $wm_img_type); - $src_img = $this->image_create_gd($this->full_src_path); - - // Reverse the offset if necessary - // When the image is positioned at the bottom - // we don't want the vertical offset to push it - // further down. We want the reverse, so we'll - // invert the offset. Same with the horizontal - // offset when the image is at the right - - $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1)); - $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1)); - - if ($this->wm_vrt_alignment == 'B') - $this->wm_vrt_offset = $this->wm_vrt_offset * -1; - - if ($this->wm_hor_alignment == 'R') - $this->wm_hor_offset = $this->wm_hor_offset * -1; - - // Set the base x and y axis values - $x_axis = $this->wm_hor_offset + $this->wm_padding; - $y_axis = $this->wm_vrt_offset + $this->wm_padding; - - // Set the vertical position - switch ($this->wm_vrt_alignment) - { - case 'T': - break; - case 'M': $y_axis += ($this->orig_height / 2) - ($wm_height / 2); - break; - case 'B': $y_axis += $this->orig_height - $wm_height; - break; - } - - // Set the horizontal position - switch ($this->wm_hor_alignment) - { - case 'L': - break; - case 'C': $x_axis += ($this->orig_width / 2) - ($wm_width / 2); - break; - case 'R': $x_axis += $this->orig_width - $wm_width; - break; - } - - // Build the finalized image - if ($wm_img_type == 3 AND function_exists('imagealphablending')) - { - @imagealphablending($src_img, TRUE); - } - - // Set RGB values for text and shadow - $rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp); - $alpha = ($rgba & 0x7F000000) >> 24; - - // make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency - if ($alpha > 0) - { - // copy the image directly, the image's alpha transparency being the sole determinant of blending - imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height); - } - else - { - // set our RGB value from above to be transparent and merge the images with the specified opacity - imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp)); - imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity); - } - - // Output the image - if ($this->dynamic_output == TRUE) - { - $this->image_display_gd($src_img); - } - else - { - if ( ! $this->image_save_gd($src_img)) - { - return FALSE; - } - } - - imagedestroy($src_img); - imagedestroy($wm_img); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Watermark - Text Version - * - * @access public - * @return bool - */ - function text_watermark() - { - if ( ! ($src_img = $this->image_create_gd())) - { - return FALSE; - } - - if ($this->wm_use_truetype == TRUE AND ! file_exists($this->wm_font_path)) - { - $this->set_error('imglib_missing_font'); - return FALSE; - } - - // Fetch source image properties - $this->get_image_properties(); - - // Set RGB values for text and shadow - $this->wm_font_color = str_replace('#', '', $this->wm_font_color); - $this->wm_shadow_color = str_replace('#', '', $this->wm_shadow_color); - - $R1 = hexdec(substr($this->wm_font_color, 0, 2)); - $G1 = hexdec(substr($this->wm_font_color, 2, 2)); - $B1 = hexdec(substr($this->wm_font_color, 4, 2)); - - $R2 = hexdec(substr($this->wm_shadow_color, 0, 2)); - $G2 = hexdec(substr($this->wm_shadow_color, 2, 2)); - $B2 = hexdec(substr($this->wm_shadow_color, 4, 2)); - - $txt_color = imagecolorclosest($src_img, $R1, $G1, $B1); - $drp_color = imagecolorclosest($src_img, $R2, $G2, $B2); - - // Reverse the vertical offset - // When the image is positioned at the bottom - // we don't want the vertical offset to push it - // further down. We want the reverse, so we'll - // invert the offset. Note: The horizontal - // offset flips itself automatically - - if ($this->wm_vrt_alignment == 'B') - $this->wm_vrt_offset = $this->wm_vrt_offset * -1; - - if ($this->wm_hor_alignment == 'R') - $this->wm_hor_offset = $this->wm_hor_offset * -1; - - // Set font width and height - // These are calculated differently depending on - // whether we are using the true type font or not - if ($this->wm_use_truetype == TRUE) - { - if ($this->wm_font_size == '') - $this->wm_font_size = '17'; - - $fontwidth = $this->wm_font_size-($this->wm_font_size/4); - $fontheight = $this->wm_font_size; - $this->wm_vrt_offset += $this->wm_font_size; - } - else - { - $fontwidth = imagefontwidth($this->wm_font_size); - $fontheight = imagefontheight($this->wm_font_size); - } - - // Set base X and Y axis values - $x_axis = $this->wm_hor_offset + $this->wm_padding; - $y_axis = $this->wm_vrt_offset + $this->wm_padding; - - // Set verticle alignment - if ($this->wm_use_drop_shadow == FALSE) - $this->wm_shadow_distance = 0; - - $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1)); - $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1)); - - switch ($this->wm_vrt_alignment) - { - case "T" : - break; - case "M": $y_axis += ($this->orig_height/2)+($fontheight/2); - break; - case "B": $y_axis += ($this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight/2)); - break; - } - - $x_shad = $x_axis + $this->wm_shadow_distance; - $y_shad = $y_axis + $this->wm_shadow_distance; - - // Set horizontal alignment - switch ($this->wm_hor_alignment) - { - case "L": - break; - case "R": - if ($this->wm_use_drop_shadow) - $x_shad += ($this->orig_width - $fontwidth*strlen($this->wm_text)); - $x_axis += ($this->orig_width - $fontwidth*strlen($this->wm_text)); - break; - case "C": - if ($this->wm_use_drop_shadow) - $x_shad += floor(($this->orig_width - $fontwidth*strlen($this->wm_text))/2); - $x_axis += floor(($this->orig_width -$fontwidth*strlen($this->wm_text))/2); - break; - } - - // Add the text to the source image - if ($this->wm_use_truetype) - { - if ($this->wm_use_drop_shadow) - imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text); - imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text); - } - else - { - if ($this->wm_use_drop_shadow) - imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color); - imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color); - } - - // Output the final image - if ($this->dynamic_output == TRUE) - { - $this->image_display_gd($src_img); - } - else - { - $this->image_save_gd($src_img); - } - - imagedestroy($src_img); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Create Image - GD - * - * This simply creates an image resource handle - * based on the type of image being processed - * - * @access public - * @param string - * @return resource - */ - function image_create_gd($path = '', $image_type = '') - { - if ($path == '') - $path = $this->full_src_path; - - if ($image_type == '') - $image_type = $this->image_type; - - - switch ($image_type) - { - case 1 : - if ( ! function_exists('imagecreatefromgif')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); - return FALSE; - } - - return imagecreatefromgif($path); - break; - case 2 : - if ( ! function_exists('imagecreatefromjpeg')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); - return FALSE; - } - - return imagecreatefromjpeg($path); - break; - case 3 : - if ( ! function_exists('imagecreatefrompng')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); - return FALSE; - } - - return imagecreatefrompng($path); - break; - - } - - $this->set_error(array('imglib_unsupported_imagecreate')); - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Write image file to disk - GD - * - * Takes an image resource as input and writes the file - * to the specified destination - * - * @access public - * @param resource - * @return bool - */ - function image_save_gd($resource) - { - switch ($this->image_type) - { - case 1 : - if ( ! function_exists('imagegif')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); - return FALSE; - } - - if ( ! @imagegif($resource, $this->full_dst_path)) - { - $this->set_error('imglib_save_failed'); - return FALSE; - } - break; - case 2 : - if ( ! function_exists('imagejpeg')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); - return FALSE; - } - - if (phpversion() == '4.4.1') - { - @touch($this->full_dst_path); // PHP 4.4.1 bug #35060 - workaround - } - - if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality)) - { - $this->set_error('imglib_save_failed'); - return FALSE; - } - break; - case 3 : - if ( ! function_exists('imagepng')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); - return FALSE; - } - - if ( ! @imagepng($resource, $this->full_dst_path)) - { - $this->set_error('imglib_save_failed'); - return FALSE; - } - break; - default : - $this->set_error(array('imglib_unsupported_imagecreate')); - return FALSE; - break; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Dynamically outputs an image - * - * @access public - * @param resource - * @return void - */ - function image_display_gd($resource) - { - header("Content-Disposition: filename={$this->source_image};"); - header("Content-Type: {$this->mime_type}"); - header('Content-Transfer-Encoding: binary'); - header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); - - switch ($this->image_type) - { - case 1 : imagegif($resource); - break; - case 2 : imagejpeg($resource, '', $this->quality); - break; - case 3 : imagepng($resource); - break; - default : echo 'Unable to display the image'; - break; - } - } - - // -------------------------------------------------------------------- - - /** - * Re-proportion Image Width/Height - * - * When creating thumbs, the desired width/height - * can end up warping the image due to an incorrect - * ratio between the full-sized image and the thumb. - * - * This function lets us re-proportion the width/height - * if users choose to maintain the aspect ratio when resizing. - * - * @access public - * @return void - */ - function image_reproportion() - { - if ( ! is_numeric($this->width) OR ! is_numeric($this->height) OR $this->width == 0 OR $this->height == 0) - return; - - if ( ! is_numeric($this->orig_width) OR ! is_numeric($this->orig_height) OR $this->orig_width == 0 OR $this->orig_height == 0) - return; - - $new_width = ceil($this->orig_width*$this->height/$this->orig_height); - $new_height = ceil($this->width*$this->orig_height/$this->orig_width); - - $ratio = (($this->orig_height/$this->orig_width) - ($this->height/$this->width)); - - if ($this->master_dim != 'width' AND $this->master_dim != 'height') - { - $this->master_dim = ($ratio < 0) ? 'width' : 'height'; - } - - if (($this->width != $new_width) AND ($this->height != $new_height)) - { - if ($this->master_dim == 'height') - { - $this->width = $new_width; - } - else - { - $this->height = $new_height; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Get image properties - * - * A helper function that gets info about the file - * - * @access public - * @param string - * @return mixed - */ - function get_image_properties($path = '', $return = FALSE) - { - // For now we require GD but we should - // find a way to determine this using IM or NetPBM - - if ($path == '') - $path = $this->full_src_path; - - if ( ! file_exists($path)) - { - $this->set_error('imglib_invalid_path'); - return FALSE; - } - - $vals = @getimagesize($path); - - $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png'); - - $mime = (isset($types[$vals['2']])) ? 'image/'.$types[$vals['2']] : 'image/jpg'; - - if ($return == TRUE) - { - $v['width'] = $vals['0']; - $v['height'] = $vals['1']; - $v['image_type'] = $vals['2']; - $v['size_str'] = $vals['3']; - $v['mime_type'] = $mime; - - return $v; - } - - $this->orig_width = $vals['0']; - $this->orig_height = $vals['1']; - $this->image_type = $vals['2']; - $this->size_str = $vals['3']; - $this->mime_type = $mime; - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Size calculator - * - * This function takes a known width x height and - * recalculates it to a new size. Only one - * new variable needs to be known - * - * $props = array( - * 'width' => $width, - * 'height' => $height, - * 'new_width' => 40, - * 'new_height' => '' - * ); - * - * @access public - * @param array - * @return array - */ - function size_calculator($vals) - { - if ( ! is_array($vals)) - { - return; - } - - $allowed = array('new_width', 'new_height', 'width', 'height'); - - foreach ($allowed as $item) - { - if ( ! isset($vals[$item]) OR $vals[$item] == '') - $vals[$item] = 0; - } - - if ($vals['width'] == 0 OR $vals['height'] == 0) - { - return $vals; - } - - if ($vals['new_width'] == 0) - { - $vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']); - } - elseif ($vals['new_height'] == 0) - { - $vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']); - } - - return $vals; - } - - // -------------------------------------------------------------------- - - /** - * Explode source_image - * - * This is a helper function that extracts the extension - * from the source_image. This function lets us deal with - * source_images with multiple periods, like: my.cool.jpg - * It returns an associative array with two elements: - * $array['ext'] = '.jpg'; - * $array['name'] = 'my.cool'; - * - * @access public - * @param array - * @return array - */ - function explode_name($source_image) - { - $ext = strrchr($source_image, '.'); - $name = ($ext === FALSE) ? $source_image : substr($source_image, 0, -strlen($ext)); - - return array('ext' => $ext, 'name' => $name); - } - - // -------------------------------------------------------------------- - - /** - * Is GD Installed? - * - * @access public - * @return bool - */ - function gd_loaded() - { - if ( ! extension_loaded('gd')) - { - if ( ! dl('gd.so')) - { - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Get GD version - * - * @access public - * @return mixed - */ - function gd_version() - { - if (function_exists('gd_info')) - { - $gd_version = @gd_info(); - $gd_version = preg_replace("/\D/", "", $gd_version['GD Version']); - - return $gd_version; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Set error message - * - * @access public - * @param string - * @return void - */ - function set_error($msg) - { - $CI =& get_instance(); - $CI->lang->load('imglib'); - - 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); - } - } - - // -------------------------------------------------------------------- - - /** - * Show error messages - * - * @access public - * @param string - * @return string - */ - function display_errors($open = '

      ', $close = '

      ') - { - $str = ''; - foreach ($this->error_msg as $val) - { - $str .= $open.$val.$close; - } - - return $str; - } - -} -// END Image_lib Class - -/* End of file Image_lib.php */ + 0) + { + $this->initialize($props); + } + + log_message('debug', "Image Lib Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize image properties + * + * Resets values in case this class is used in a loop + * + * @access public + * @return void + */ + function clear() + { + $props = array('source_folder', 'dest_folder', 'source_image', 'full_src_path', 'full_dst_path', 'new_image', 'image_type', 'size_str', 'quality', 'orig_width', 'orig_height', 'rotation_angle', 'x_axis', 'y_axis', 'create_fnc', 'copy_fnc', 'wm_overlay_path', 'wm_use_truetype', 'dynamic_output', 'wm_font_size', 'wm_text', 'wm_vrt_alignment', 'wm_hor_alignment', 'wm_padding', 'wm_hor_offset', 'wm_vrt_offset', 'wm_font_color', 'wm_use_drop_shadow', 'wm_shadow_color', 'wm_shadow_distance', 'wm_opacity'); + + foreach ($props as $val) + { + $this->$val = ''; + } + + // special consideration for master_dim + $this->master_dim = 'auto'; + } + + // -------------------------------------------------------------------- + + /** + * initialize image preferences + * + * @access public + * @param array + * @return bool + */ + function initialize($props = array()) + { + /* + * Convert array elements into class variables + */ + if (count($props) > 0) + { + foreach ($props as $key => $val) + { + $this->$key = $val; + } + } + + /* + * Is there a source image? + * + * If not, there's no reason to continue + * + */ + if ($this->source_image == '') + { + $this->set_error('imglib_source_image_required'); + return FALSE; + } + + /* + * Is getimagesize() Available? + * + * We use it to determine the image properties (width/height). + * Note: We need to figure out how to determine image + * properties using ImageMagick and NetPBM + * + */ + if ( ! function_exists('getimagesize')) + { + $this->set_error('imglib_gd_required_for_props'); + return FALSE; + } + + $this->image_library = strtolower($this->image_library); + + /* + * Set the full server path + * + * The source image may or may not contain a path. + * Either way, we'll try use realpath to generate the + * full server path in order to more reliably read it. + * + */ + if (function_exists('realpath') AND @realpath($this->source_image) !== FALSE) + { + $full_source_path = str_replace("\\", "/", realpath($this->source_image)); + } + else + { + $full_source_path = $this->source_image; + } + + $x = explode('/', $full_source_path); + $this->source_image = end($x); + $this->source_folder = str_replace($this->source_image, '', $full_source_path); + + // Set the Image Properties + if ( ! $this->get_image_properties($this->source_folder.$this->source_image)) + { + return FALSE; + } + + /* + * Assign the "new" image name/path + * + * If the user has set a "new_image" name it means + * we are making a copy of the source image. If not + * it means we are altering the original. We'll + * set the destination filename and path accordingly. + * + */ + if ($this->new_image == '') + { + $this->dest_image = $this->source_image; + $this->dest_folder = $this->source_folder; + } + else + { + if (strpos($this->new_image, '/') === FALSE) + { + $this->dest_folder = $this->source_folder; + $this->dest_image = $this->new_image; + } + else + { + if (function_exists('realpath') AND @realpath($this->new_image) !== FALSE) + { + $full_dest_path = str_replace("\\", "/", realpath($this->new_image)); + } + else + { + $full_dest_path = $this->new_image; + } + + // Is there a file name? + if ( ! preg_match("#\.(jpg|jpeg|gif|png)$#i", $full_dest_path)) + { + $this->dest_folder = $full_dest_path.'/'; + $this->dest_image = $this->source_image; + } + else + { + $x = explode('/', $full_dest_path); + $this->dest_image = end($x); + $this->dest_folder = str_replace($this->dest_image, '', $full_dest_path); + } + } + } + + /* + * Compile the finalized filenames/paths + * + * We'll create two master strings containing the + * full server path to the source image and the + * full server path to the destination image. + * We'll also split the destination image name + * so we can insert the thumbnail marker if needed. + * + */ + if ($this->create_thumb === FALSE OR $this->thumb_marker == '') + { + $this->thumb_marker = ''; + } + + $xp = $this->explode_name($this->dest_image); + + $filename = $xp['name']; + $file_ext = $xp['ext']; + + $this->full_src_path = $this->source_folder.$this->source_image; + $this->full_dst_path = $this->dest_folder.$filename.$this->thumb_marker.$file_ext; + + /* + * Should we maintain image proportions? + * + * When creating thumbs or copies, the target width/height + * might not be in correct proportion with the source + * image's width/height. We'll recalculate it here. + * + */ + if ($this->maintain_ratio === TRUE && ($this->width != '' AND $this->height != '')) + { + $this->image_reproportion(); + } + + /* + * Was a width and height specified? + * + * If the destination width/height was + * not submitted we will use the values + * from the actual file + * + */ + if ($this->width == '') + $this->width = $this->orig_width; + + if ($this->height == '') + $this->height = $this->orig_height; + + // Set the quality + $this->quality = trim(str_replace("%", "", $this->quality)); + + if ($this->quality == '' OR $this->quality == 0 OR ! is_numeric($this->quality)) + $this->quality = 90; + + // Set the x/y coordinates + $this->x_axis = ($this->x_axis == '' OR ! is_numeric($this->x_axis)) ? 0 : $this->x_axis; + $this->y_axis = ($this->y_axis == '' OR ! is_numeric($this->y_axis)) ? 0 : $this->y_axis; + + // Watermark-related Stuff... + if ($this->wm_font_color != '') + { + if (strlen($this->wm_font_color) == 6) + { + $this->wm_font_color = '#'.$this->wm_font_color; + } + } + + if ($this->wm_shadow_color != '') + { + if (strlen($this->wm_shadow_color) == 6) + { + $this->wm_shadow_color = '#'.$this->wm_shadow_color; + } + } + + if ($this->wm_overlay_path != '') + { + $this->wm_overlay_path = str_replace("\\", "/", realpath($this->wm_overlay_path)); + } + + if ($this->wm_shadow_color != '') + { + $this->wm_use_drop_shadow = TRUE; + } + + if ($this->wm_font_path != '') + { + $this->wm_use_truetype = TRUE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Image Resize + * + * This is a wrapper function that chooses the proper + * resize function based on the protocol specified + * + * @access public + * @return bool + */ + function resize() + { + $protocol = 'image_process_'.$this->image_library; + + if (preg_match('/gd2$/i', $protocol)) + { + $protocol = 'image_process_gd'; + } + + return $this->$protocol('resize'); + } + + // -------------------------------------------------------------------- + + /** + * Image Crop + * + * This is a wrapper function that chooses the proper + * cropping function based on the protocol specified + * + * @access public + * @return bool + */ + function crop() + { + $protocol = 'image_process_'.$this->image_library; + + if (preg_match('/gd2$/i', $protocol)) + { + $protocol = 'image_process_gd'; + } + + return $this->$protocol('crop'); + } + + // -------------------------------------------------------------------- + + /** + * Image Rotate + * + * This is a wrapper function that chooses the proper + * rotation function based on the protocol specified + * + * @access public + * @return bool + */ + function rotate() + { + // Allowed rotation values + $degs = array(90, 180, 270, 'vrt', 'hor'); + + if ($this->rotation_angle == '' OR ! in_array($this->rotation_angle, $degs)) + { + $this->set_error('imglib_rotation_angle_required'); + return FALSE; + } + + // Reassign the width and height + if ($this->rotation_angle == 90 OR $this->rotation_angle == 270) + { + $this->width = $this->orig_height; + $this->height = $this->orig_width; + } + else + { + $this->width = $this->orig_width; + $this->height = $this->orig_height; + } + + + // Choose resizing function + if ($this->image_library == 'imagemagick' OR $this->image_library == 'netpbm') + { + $protocol = 'image_process_'.$this->image_library; + + return $this->$protocol('rotate'); + } + + if ($this->rotation_angle == 'hor' OR $this->rotation_angle == 'vrt') + { + return $this->image_mirror_gd(); + } + else + { + return $this->image_rotate_gd(); + } + } + + // -------------------------------------------------------------------- + + /** + * Image Process Using GD/GD2 + * + * This function will resize or crop + * + * @access public + * @param string + * @return bool + */ + function image_process_gd($action = 'resize') + { + $v2_override = FALSE; + + // If the target width/height match the source, AND if the new file name is not equal to the old file name + // we'll simply make a copy of the original with the new name... assuming dynamic rendering is off. + if ($this->dynamic_output === FALSE) + { + if ($this->orig_width == $this->width AND $this->orig_height == $this->height) + { + if ($this->source_image != $this->new_image) + { + if (@copy($this->full_src_path, $this->full_dst_path)) + { + @chmod($this->full_dst_path, DIR_WRITE_MODE); + } + } + + return TRUE; + } + } + + // Let's set up our values based on the action + if ($action == 'crop') + { + // Reassign the source width/height if cropping + $this->orig_width = $this->width; + $this->orig_height = $this->height; + + // GD 2.0 has a cropping bug so we'll test for it + if ($this->gd_version() !== FALSE) + { + $gd_version = str_replace('0', '', $this->gd_version()); + $v2_override = ($gd_version == 2) ? TRUE : FALSE; + } + } + else + { + // If resizing the x/y axis must be zero + $this->x_axis = 0; + $this->y_axis = 0; + } + + // Create the image handle + if ( ! ($src_img = $this->image_create_gd())) + { + return FALSE; + } + + // Create The Image + // + // old conditional which users report cause problems with shared GD libs who report themselves as "2.0 or greater" + // it appears that this is no longer the issue that it was in 2004, so we've removed it, retaining it in the comment + // below should that ever prove inaccurate. + // + // if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor') AND $v2_override == FALSE) + if ($this->image_library == 'gd2' AND function_exists('imagecreatetruecolor')) + { + $create = 'imagecreatetruecolor'; + $copy = 'imagecopyresampled'; + } + else + { + $create = 'imagecreate'; + $copy = 'imagecopyresized'; + } + + $dst_img = $create($this->width, $this->height); + $copy($dst_img, $src_img, 0, 0, $this->x_axis, $this->y_axis, $this->width, $this->height, $this->orig_width, $this->orig_height); + + // Show the image + if ($this->dynamic_output == TRUE) + { + $this->image_display_gd($dst_img); + } + else + { + // Or save it + if ( ! $this->image_save_gd($dst_img)) + { + return FALSE; + } + } + + // Kill the file handles + imagedestroy($dst_img); + imagedestroy($src_img); + + // Set the file to 777 + @chmod($this->full_dst_path, DIR_WRITE_MODE); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Image Process Using ImageMagick + * + * This function will resize, crop or rotate + * + * @access public + * @param string + * @return bool + */ + function image_process_imagemagick($action = 'resize') + { + // Do we have a vaild library path? + if ($this->library_path == '') + { + $this->set_error('imglib_libpath_invalid'); + return FALSE; + } + + if ( ! preg_match("/convert$/i", $this->library_path)) + { + $this->library_path = rtrim($this->library_path, '/').'/'; + + $this->library_path .= 'convert'; + } + + // Execute the command + $cmd = $this->library_path." -quality ".$this->quality; + + if ($action == 'crop') + { + $cmd .= " -crop ".$this->width."x".$this->height."+".$this->x_axis."+".$this->y_axis." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1"; + } + elseif ($action == 'rotate') + { + switch ($this->rotation_angle) + { + case 'hor' : $angle = '-flop'; + break; + case 'vrt' : $angle = '-flip'; + break; + default : $angle = '-rotate '.$this->rotation_angle; + break; + } + + $cmd .= " ".$angle." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1"; + } + else // Resize + { + $cmd .= " -resize ".$this->width."x".$this->height." \"$this->full_src_path\" \"$this->full_dst_path\" 2>&1"; + } + + $retval = 1; + + @exec($cmd, $output, $retval); + + // Did it work? + if ($retval > 0) + { + $this->set_error('imglib_image_process_failed'); + return FALSE; + } + + // Set the file to 777 + @chmod($this->full_dst_path, DIR_WRITE_MODE); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Image Process Using NetPBM + * + * This function will resize, crop or rotate + * + * @access public + * @param string + * @return bool + */ + function image_process_netpbm($action = 'resize') + { + if ($this->library_path == '') + { + $this->set_error('imglib_libpath_invalid'); + return FALSE; + } + + // Build the resizing command + switch ($this->image_type) + { + case 1 : + $cmd_in = 'giftopnm'; + $cmd_out = 'ppmtogif'; + break; + case 2 : + $cmd_in = 'jpegtopnm'; + $cmd_out = 'ppmtojpeg'; + break; + case 3 : + $cmd_in = 'pngtopnm'; + $cmd_out = 'ppmtopng'; + break; + } + + if ($action == 'crop') + { + $cmd_inner = 'pnmcut -left '.$this->x_axis.' -top '.$this->y_axis.' -width '.$this->width.' -height '.$this->height; + } + elseif ($action == 'rotate') + { + switch ($this->rotation_angle) + { + case 90 : $angle = 'r270'; + break; + case 180 : $angle = 'r180'; + break; + case 270 : $angle = 'r90'; + break; + case 'vrt' : $angle = 'tb'; + break; + case 'hor' : $angle = 'lr'; + break; + } + + $cmd_inner = 'pnmflip -'.$angle.' '; + } + else // Resize + { + $cmd_inner = 'pnmscale -xysize '.$this->width.' '.$this->height; + } + + $cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp'; + + $retval = 1; + + @exec($cmd, $output, $retval); + + // Did it work? + if ($retval > 0) + { + $this->set_error('imglib_image_process_failed'); + return FALSE; + } + + // With NetPBM we have to create a temporary image. + // If you try manipulating the original it fails so + // we have to rename the temp file. + copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path); + unlink ($this->dest_folder.'netpbm.tmp'); + @chmod($this->full_dst_path, DIR_WRITE_MODE); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Image Rotate Using GD + * + * @access public + * @return bool + */ + function image_rotate_gd() + { + // Is Image Rotation Supported? + // this function is only supported as of PHP 4.3 + if ( ! function_exists('imagerotate')) + { + $this->set_error('imglib_rotate_unsupported'); + return FALSE; + } + + // Create the image handle + if ( ! ($src_img = $this->image_create_gd())) + { + return FALSE; + } + + // Set the background color + // This won't work with transparent PNG files so we are + // going to have to figure out how to determine the color + // of the alpha channel in a future release. + + $white = imagecolorallocate($src_img, 255, 255, 255); + + // Rotate it! + $dst_img = imagerotate($src_img, $this->rotation_angle, $white); + + // Save the Image + if ($this->dynamic_output == TRUE) + { + $this->image_display_gd($dst_img); + } + else + { + // Or save it + if ( ! $this->image_save_gd($dst_img)) + { + return FALSE; + } + } + + // Kill the file handles + imagedestroy($dst_img); + imagedestroy($src_img); + + // Set the file to 777 + + @chmod($this->full_dst_path, DIR_WRITE_MODE); + + return true; + } + + // -------------------------------------------------------------------- + + /** + * Create Mirror Image using GD + * + * This function will flip horizontal or vertical + * + * @access public + * @return bool + */ + function image_mirror_gd() + { + if ( ! $src_img = $this->image_create_gd()) + { + return FALSE; + } + + $width = $this->orig_width; + $height = $this->orig_height; + + if ($this->rotation_angle == 'hor') + { + for ($i = 0; $i < $height; $i++) + { + $left = 0; + $right = $width-1; + + while ($left < $right) + { + $cl = imagecolorat($src_img, $left, $i); + $cr = imagecolorat($src_img, $right, $i); + + imagesetpixel($src_img, $left, $i, $cr); + imagesetpixel($src_img, $right, $i, $cl); + + $left++; + $right--; + } + } + } + else + { + for ($i = 0; $i < $width; $i++) + { + $top = 0; + $bot = $height-1; + + while ($top < $bot) + { + $ct = imagecolorat($src_img, $i, $top); + $cb = imagecolorat($src_img, $i, $bot); + + imagesetpixel($src_img, $i, $top, $cb); + imagesetpixel($src_img, $i, $bot, $ct); + + $top++; + $bot--; + } + } + } + + // Show the image + if ($this->dynamic_output == TRUE) + { + $this->image_display_gd($src_img); + } + else + { + // Or save it + if ( ! $this->image_save_gd($src_img)) + { + return FALSE; + } + } + + // Kill the file handles + imagedestroy($src_img); + + // Set the file to 777 + @chmod($this->full_dst_path, DIR_WRITE_MODE); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Image Watermark + * + * This is a wrapper function that chooses the type + * of watermarking based on the specified preference. + * + * @access public + * @param string + * @return bool + */ + function watermark() + { + if ($this->wm_type == 'overlay') + { + return $this->overlay_watermark(); + } + else + { + return $this->text_watermark(); + } + } + + // -------------------------------------------------------------------- + + /** + * Watermark - Graphic Version + * + * @access public + * @return bool + */ + function overlay_watermark() + { + if ( ! function_exists('imagecolortransparent')) + { + $this->set_error('imglib_gd_required'); + return FALSE; + } + + // Fetch source image properties + $this->get_image_properties(); + + // Fetch watermark image properties + $props = $this->get_image_properties($this->wm_overlay_path, TRUE); + $wm_img_type = $props['image_type']; + $wm_width = $props['width']; + $wm_height = $props['height']; + + // Create two image resources + $wm_img = $this->image_create_gd($this->wm_overlay_path, $wm_img_type); + $src_img = $this->image_create_gd($this->full_src_path); + + // Reverse the offset if necessary + // When the image is positioned at the bottom + // we don't want the vertical offset to push it + // further down. We want the reverse, so we'll + // invert the offset. Same with the horizontal + // offset when the image is at the right + + $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1)); + $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1)); + + if ($this->wm_vrt_alignment == 'B') + $this->wm_vrt_offset = $this->wm_vrt_offset * -1; + + if ($this->wm_hor_alignment == 'R') + $this->wm_hor_offset = $this->wm_hor_offset * -1; + + // Set the base x and y axis values + $x_axis = $this->wm_hor_offset + $this->wm_padding; + $y_axis = $this->wm_vrt_offset + $this->wm_padding; + + // Set the vertical position + switch ($this->wm_vrt_alignment) + { + case 'T': + break; + case 'M': $y_axis += ($this->orig_height / 2) - ($wm_height / 2); + break; + case 'B': $y_axis += $this->orig_height - $wm_height; + break; + } + + // Set the horizontal position + switch ($this->wm_hor_alignment) + { + case 'L': + break; + case 'C': $x_axis += ($this->orig_width / 2) - ($wm_width / 2); + break; + case 'R': $x_axis += $this->orig_width - $wm_width; + break; + } + + // Build the finalized image + if ($wm_img_type == 3 AND function_exists('imagealphablending')) + { + @imagealphablending($src_img, TRUE); + } + + // Set RGB values for text and shadow + $rgba = imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp); + $alpha = ($rgba & 0x7F000000) >> 24; + + // make a best guess as to whether we're dealing with an image with alpha transparency or no/binary transparency + if ($alpha > 0) + { + // copy the image directly, the image's alpha transparency being the sole determinant of blending + imagecopy($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height); + } + else + { + // set our RGB value from above to be transparent and merge the images with the specified opacity + imagecolortransparent($wm_img, imagecolorat($wm_img, $this->wm_x_transp, $this->wm_y_transp)); + imagecopymerge($src_img, $wm_img, $x_axis, $y_axis, 0, 0, $wm_width, $wm_height, $this->wm_opacity); + } + + // Output the image + if ($this->dynamic_output == TRUE) + { + $this->image_display_gd($src_img); + } + else + { + if ( ! $this->image_save_gd($src_img)) + { + return FALSE; + } + } + + imagedestroy($src_img); + imagedestroy($wm_img); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Watermark - Text Version + * + * @access public + * @return bool + */ + function text_watermark() + { + if ( ! ($src_img = $this->image_create_gd())) + { + return FALSE; + } + + if ($this->wm_use_truetype == TRUE AND ! file_exists($this->wm_font_path)) + { + $this->set_error('imglib_missing_font'); + return FALSE; + } + + // Fetch source image properties + $this->get_image_properties(); + + // Set RGB values for text and shadow + $this->wm_font_color = str_replace('#', '', $this->wm_font_color); + $this->wm_shadow_color = str_replace('#', '', $this->wm_shadow_color); + + $R1 = hexdec(substr($this->wm_font_color, 0, 2)); + $G1 = hexdec(substr($this->wm_font_color, 2, 2)); + $B1 = hexdec(substr($this->wm_font_color, 4, 2)); + + $R2 = hexdec(substr($this->wm_shadow_color, 0, 2)); + $G2 = hexdec(substr($this->wm_shadow_color, 2, 2)); + $B2 = hexdec(substr($this->wm_shadow_color, 4, 2)); + + $txt_color = imagecolorclosest($src_img, $R1, $G1, $B1); + $drp_color = imagecolorclosest($src_img, $R2, $G2, $B2); + + // Reverse the vertical offset + // When the image is positioned at the bottom + // we don't want the vertical offset to push it + // further down. We want the reverse, so we'll + // invert the offset. Note: The horizontal + // offset flips itself automatically + + if ($this->wm_vrt_alignment == 'B') + $this->wm_vrt_offset = $this->wm_vrt_offset * -1; + + if ($this->wm_hor_alignment == 'R') + $this->wm_hor_offset = $this->wm_hor_offset * -1; + + // Set font width and height + // These are calculated differently depending on + // whether we are using the true type font or not + if ($this->wm_use_truetype == TRUE) + { + if ($this->wm_font_size == '') + $this->wm_font_size = '17'; + + $fontwidth = $this->wm_font_size-($this->wm_font_size/4); + $fontheight = $this->wm_font_size; + $this->wm_vrt_offset += $this->wm_font_size; + } + else + { + $fontwidth = imagefontwidth($this->wm_font_size); + $fontheight = imagefontheight($this->wm_font_size); + } + + // Set base X and Y axis values + $x_axis = $this->wm_hor_offset + $this->wm_padding; + $y_axis = $this->wm_vrt_offset + $this->wm_padding; + + // Set verticle alignment + if ($this->wm_use_drop_shadow == FALSE) + $this->wm_shadow_distance = 0; + + $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1)); + $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1)); + + switch ($this->wm_vrt_alignment) + { + case "T" : + break; + case "M": $y_axis += ($this->orig_height/2)+($fontheight/2); + break; + case "B": $y_axis += ($this->orig_height - $fontheight - $this->wm_shadow_distance - ($fontheight/2)); + break; + } + + $x_shad = $x_axis + $this->wm_shadow_distance; + $y_shad = $y_axis + $this->wm_shadow_distance; + + // Set horizontal alignment + switch ($this->wm_hor_alignment) + { + case "L": + break; + case "R": + if ($this->wm_use_drop_shadow) + $x_shad += ($this->orig_width - $fontwidth*strlen($this->wm_text)); + $x_axis += ($this->orig_width - $fontwidth*strlen($this->wm_text)); + break; + case "C": + if ($this->wm_use_drop_shadow) + $x_shad += floor(($this->orig_width - $fontwidth*strlen($this->wm_text))/2); + $x_axis += floor(($this->orig_width -$fontwidth*strlen($this->wm_text))/2); + break; + } + + // Add the text to the source image + if ($this->wm_use_truetype) + { + if ($this->wm_use_drop_shadow) + imagettftext($src_img, $this->wm_font_size, 0, $x_shad, $y_shad, $drp_color, $this->wm_font_path, $this->wm_text); + imagettftext($src_img, $this->wm_font_size, 0, $x_axis, $y_axis, $txt_color, $this->wm_font_path, $this->wm_text); + } + else + { + if ($this->wm_use_drop_shadow) + imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color); + imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color); + } + + // Output the final image + if ($this->dynamic_output == TRUE) + { + $this->image_display_gd($src_img); + } + else + { + $this->image_save_gd($src_img); + } + + imagedestroy($src_img); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Create Image - GD + * + * This simply creates an image resource handle + * based on the type of image being processed + * + * @access public + * @param string + * @return resource + */ + function image_create_gd($path = '', $image_type = '') + { + if ($path == '') + $path = $this->full_src_path; + + if ($image_type == '') + $image_type = $this->image_type; + + + switch ($image_type) + { + case 1 : + if ( ! function_exists('imagecreatefromgif')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); + return FALSE; + } + + return imagecreatefromgif($path); + break; + case 2 : + if ( ! function_exists('imagecreatefromjpeg')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); + return FALSE; + } + + return imagecreatefromjpeg($path); + break; + case 3 : + if ( ! function_exists('imagecreatefrompng')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); + return FALSE; + } + + return imagecreatefrompng($path); + break; + + } + + $this->set_error(array('imglib_unsupported_imagecreate')); + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Write image file to disk - GD + * + * Takes an image resource as input and writes the file + * to the specified destination + * + * @access public + * @param resource + * @return bool + */ + function image_save_gd($resource) + { + switch ($this->image_type) + { + case 1 : + if ( ! function_exists('imagegif')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); + return FALSE; + } + + if ( ! @imagegif($resource, $this->full_dst_path)) + { + $this->set_error('imglib_save_failed'); + return FALSE; + } + break; + case 2 : + if ( ! function_exists('imagejpeg')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); + return FALSE; + } + + if (phpversion() == '4.4.1') + { + @touch($this->full_dst_path); // PHP 4.4.1 bug #35060 - workaround + } + + if ( ! @imagejpeg($resource, $this->full_dst_path, $this->quality)) + { + $this->set_error('imglib_save_failed'); + return FALSE; + } + break; + case 3 : + if ( ! function_exists('imagepng')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); + return FALSE; + } + + if ( ! @imagepng($resource, $this->full_dst_path)) + { + $this->set_error('imglib_save_failed'); + return FALSE; + } + break; + default : + $this->set_error(array('imglib_unsupported_imagecreate')); + return FALSE; + break; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Dynamically outputs an image + * + * @access public + * @param resource + * @return void + */ + function image_display_gd($resource) + { + header("Content-Disposition: filename={$this->source_image};"); + header("Content-Type: {$this->mime_type}"); + header('Content-Transfer-Encoding: binary'); + header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); + + switch ($this->image_type) + { + case 1 : imagegif($resource); + break; + case 2 : imagejpeg($resource, '', $this->quality); + break; + case 3 : imagepng($resource); + break; + default : echo 'Unable to display the image'; + break; + } + } + + // -------------------------------------------------------------------- + + /** + * Re-proportion Image Width/Height + * + * When creating thumbs, the desired width/height + * can end up warping the image due to an incorrect + * ratio between the full-sized image and the thumb. + * + * This function lets us re-proportion the width/height + * if users choose to maintain the aspect ratio when resizing. + * + * @access public + * @return void + */ + function image_reproportion() + { + if ( ! is_numeric($this->width) OR ! is_numeric($this->height) OR $this->width == 0 OR $this->height == 0) + return; + + if ( ! is_numeric($this->orig_width) OR ! is_numeric($this->orig_height) OR $this->orig_width == 0 OR $this->orig_height == 0) + return; + + $new_width = ceil($this->orig_width*$this->height/$this->orig_height); + $new_height = ceil($this->width*$this->orig_height/$this->orig_width); + + $ratio = (($this->orig_height/$this->orig_width) - ($this->height/$this->width)); + + if ($this->master_dim != 'width' AND $this->master_dim != 'height') + { + $this->master_dim = ($ratio < 0) ? 'width' : 'height'; + } + + if (($this->width != $new_width) AND ($this->height != $new_height)) + { + if ($this->master_dim == 'height') + { + $this->width = $new_width; + } + else + { + $this->height = $new_height; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Get image properties + * + * A helper function that gets info about the file + * + * @access public + * @param string + * @return mixed + */ + function get_image_properties($path = '', $return = FALSE) + { + // For now we require GD but we should + // find a way to determine this using IM or NetPBM + + if ($path == '') + $path = $this->full_src_path; + + if ( ! file_exists($path)) + { + $this->set_error('imglib_invalid_path'); + return FALSE; + } + + $vals = @getimagesize($path); + + $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png'); + + $mime = (isset($types[$vals['2']])) ? 'image/'.$types[$vals['2']] : 'image/jpg'; + + if ($return == TRUE) + { + $v['width'] = $vals['0']; + $v['height'] = $vals['1']; + $v['image_type'] = $vals['2']; + $v['size_str'] = $vals['3']; + $v['mime_type'] = $mime; + + return $v; + } + + $this->orig_width = $vals['0']; + $this->orig_height = $vals['1']; + $this->image_type = $vals['2']; + $this->size_str = $vals['3']; + $this->mime_type = $mime; + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Size calculator + * + * This function takes a known width x height and + * recalculates it to a new size. Only one + * new variable needs to be known + * + * $props = array( + * 'width' => $width, + * 'height' => $height, + * 'new_width' => 40, + * 'new_height' => '' + * ); + * + * @access public + * @param array + * @return array + */ + function size_calculator($vals) + { + if ( ! is_array($vals)) + { + return; + } + + $allowed = array('new_width', 'new_height', 'width', 'height'); + + foreach ($allowed as $item) + { + if ( ! isset($vals[$item]) OR $vals[$item] == '') + $vals[$item] = 0; + } + + if ($vals['width'] == 0 OR $vals['height'] == 0) + { + return $vals; + } + + if ($vals['new_width'] == 0) + { + $vals['new_width'] = ceil($vals['width']*$vals['new_height']/$vals['height']); + } + elseif ($vals['new_height'] == 0) + { + $vals['new_height'] = ceil($vals['new_width']*$vals['height']/$vals['width']); + } + + return $vals; + } + + // -------------------------------------------------------------------- + + /** + * Explode source_image + * + * This is a helper function that extracts the extension + * from the source_image. This function lets us deal with + * source_images with multiple periods, like: my.cool.jpg + * It returns an associative array with two elements: + * $array['ext'] = '.jpg'; + * $array['name'] = 'my.cool'; + * + * @access public + * @param array + * @return array + */ + function explode_name($source_image) + { + $ext = strrchr($source_image, '.'); + $name = ($ext === FALSE) ? $source_image : substr($source_image, 0, -strlen($ext)); + + return array('ext' => $ext, 'name' => $name); + } + + // -------------------------------------------------------------------- + + /** + * Is GD Installed? + * + * @access public + * @return bool + */ + function gd_loaded() + { + if ( ! extension_loaded('gd')) + { + if ( ! dl('gd.so')) + { + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Get GD version + * + * @access public + * @return mixed + */ + function gd_version() + { + if (function_exists('gd_info')) + { + $gd_version = @gd_info(); + $gd_version = preg_replace("/\D/", "", $gd_version['GD Version']); + + return $gd_version; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Set error message + * + * @access public + * @param string + * @return void + */ + function set_error($msg) + { + $CI =& get_instance(); + + if (is_array($msg)) + { + foreach ($msg as $val) + { + + $msg = (T_($val) == FALSE) ? $val : T_($val); + $this->error_msg[] = $msg; + log_message('error', $msg); + } + } + else + { + $msg = (T_($msg) == FALSE) ? $msg : T_($msg); + $this->error_msg[] = $msg; + log_message('error', $msg); + } + } + + // -------------------------------------------------------------------- + + /** + * Show error messages + * + * @access public + * @param string + * @return string + */ + function display_errors($open = '

      ', $close = '

      ') + { + $str = ''; + foreach ($this->error_msg as $val) + { + $str .= $open.$val.$close; + } + + return $str; + } + +} +// END Image_lib Class + +/* End of file Image_lib.php */ /* Location: ./system/libraries/Image_lib.php */ \ No newline at end of file diff --git a/system/libraries/Input.php b/system/libraries/Input.php index ed87898..60b0124 100644 --- a/system/libraries/Input.php +++ b/system/libraries/Input.php @@ -1,1067 +1,1067 @@ - '[removed]', - 'document.write' => '[removed]', - '.parentNode' => '[removed]', - '.innerHTML' => '[removed]', - 'window.location' => '[removed]', - '-moz-binding' => '[removed]', - '' => '-->', - ' '<![CDATA[' - ); - /* never allowed, regex replacement */ - var $never_allowed_regex = array( - "javascript\s*:" => '[removed]', - "expression\s*(\(|&\#40;)" => '[removed]', // CSS and IE - "vbscript\s*:" => '[removed]', // IE, surprise! - "Redirect\s+302" => '[removed]' - ); - - /** - * Constructor - * - * Sets whether to globally enable the XSS processing - * and whether to allow the $_GET array - * - * @access public - */ - function CI_Input() - { - log_message('debug', "Input Class Initialized"); - - $CFG =& load_class('Config'); - $this->use_xss_clean = ($CFG->item('global_xss_filtering') === TRUE) ? TRUE : FALSE; - $this->allow_get_array = ($CFG->item('enable_query_strings') === TRUE) ? TRUE : FALSE; - $this->_sanitize_globals(); - } - - // -------------------------------------------------------------------- - - /** - * 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() - { - // Would kind of 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 security. - // This is effectively the same as register_globals = off - foreach (array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_ENV, (isset($_SESSION) && is_array($_SESSION)) ? $_SESSION : array()) as $global) - { - if ( ! is_array($global)) - { - if ( ! in_array($global, $protected)) - { - unset($GLOBALS[$global]); - } - } - else - { - foreach ($global as $key => $val) - { - if ( ! in_array($key, $protected)) - { - unset($GLOBALS[$key]); - } - - if (is_array($val)) - { - foreach($val as $k => $v) - { - if ( ! in_array($k, $protected)) - { - unset($GLOBALS[$k]); - } - } - } - } - } - } - - // Is $_GET data allowed? If not we'll set the $_GET to an empty array - if ($this->allow_get_array == FALSE) - { - $_GET = array(); - } - else - { - $_GET = $this->_clean_input_data($_GET); - } - - // Clean $_POST Data - $_POST = $this->_clean_input_data($_POST); - - // Clean $_COOKIE Data - // 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']); - $_COOKIE = $this->_clean_input_data($_COOKIE); - - 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 - if (get_magic_quotes_gpc()) - { - $str = stripslashes($str); - } - - // Should we filter the input data? - if ($this->use_xss_clean === TRUE) - { - $str = $this->xss_clean($str); - } - - // Standardize newlines - if (strpos($str, "\r") !== FALSE) - { - $str = str_replace(array("\r\n", "\r"), "\n", $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.'); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * 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->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 = '', $xss_clean = FALSE) - { - 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 = '', $xss_clean = FALSE) - { - 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); - } - - // -------------------------------------------------------------------- - - /** - * 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 - * - * @access public - * @return string - */ - function ip_address() - { - if ($this->ip_address !== FALSE) - { - return $this->ip_address; - } - - if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR')) - { - $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY); - $proxies = is_array($proxies) ? $proxies : array($proxies); - - $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; - } - elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP')) - { - $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; - } - elseif ($this->server('REMOTE_ADDR')) - { - $this->ip_address = $_SERVER['REMOTE_ADDR']; - } - elseif ($this->server('HTTP_CLIENT_IP')) - { - $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; - } - elseif ($this->server('HTTP_X_FORWARDED_FOR')) - { - $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; - } - - if ($this->ip_address === FALSE) - { - $this->ip_address = '0.0.0.0'; - return $this->ip_address; - } - - if (strstr($this->ip_address, ',')) - { - $x = explode(',', $this->ip_address); - $this->ip_address = trim(end($x)); - } - - if ( ! $this->valid_ip($this->ip_address)) - { - $this->ip_address = '0.0.0.0'; - } - - return $this->ip_address; - } - - // -------------------------------------------------------------------- - - /** - * Validate IP Address - * - * Updated version suggested by Geert De Deckere - * - * @access public - * @param string - * @return string - */ - function valid_ip($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; - } - - // -------------------------------------------------------------------- - - /** - * 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; - } - - // -------------------------------------------------------------------- - - /** - * Filename Security - * - * @access public - * @param string - * @return string - */ - function filename_security($str) - { - $bad = array( - "../", - "./", - "", - "<", - ">", - "'", - '"', - '&', - '$', - '#', - '{', - '}', - '[', - ']', - '=', - ';', - '?', - "%20", - "%22", - "%3c", // < - "%253c", // < - "%3e", // > - "%0e", // > - "%28", // ( - "%29", // ) - "%2528", // ( - "%26", // & - "%24", // $ - "%3f", // ? - "%3b", // ; - "%3d" // = - ); - - return stripslashes(str_replace($bad, '', $str)); - } - - // -------------------------------------------------------------------- - - /** - * 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://blog.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 - * - * @access public - * @param string - * @return string - */ - 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 = $this->_remove_invisible_characters($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); - - /* - * 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, '_html_entity_decode_callback'), $str); - - /* - * Remove Invisible Characters Again! - */ - $str = $this->_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; - - /* - * Not Allowed Under Any Conditions - */ - - foreach ($this->never_allowed_str as $key => $val) - { - $str = str_replace($key, $val, $str); - } - - foreach ($this->never_allowed_regex as $key => $val) - { - $str = preg_replace("#".$key."#i", $val, $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', '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 JavaScript Event Handlers - * - * Note: This code is a little blunt. It removes - * the event handler and anything up to the closing >, - * but it's unlikely to be a problem. - * - */ - $event_handlers = array('[^a-z_\-]on\w*','xmlns'); - - if ($is_image === TRUE) - { - /* - * Adobe Photoshop puts XML metadata into JFIF images, including namespacing, - * so we have to allow this for images. -Paul - */ - unset($event_handlers[array_search('xmlns', $event_handlers)]); - } - - $str = preg_replace("#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str); - - /* - * 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 - * - */ - foreach ($this->never_allowed_str as $key => $val) - { - $str = str_replace($key, $val, $str); - } - - foreach ($this->never_allowed_regex as $key => $val) - { - $str = preg_replace("#".$key."#i", $val, $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) - { - if ($str == $converted_string) - { - return TRUE; - } - else - { - return FALSE; - } - } - - log_message('debug', "XSS Filtering completed"); - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Random Hash for protecting URLs - * - * @access public - * @return string - */ - function xss_hash() - { - if ($this->xss_hash == '') - { - if (phpversion() >= 4.2) - mt_srand(); - else - mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff); - - $this->xss_hash = md5(time() + mt_rand(0, 1999999999)); - } - - return $this->xss_hash; - } - - // -------------------------------------------------------------------- - - /** - * Remove Invisible Characters - * - * This prevents sandwiching null characters - * between ascii characters, like Java\0script. - * - * @access public - * @param string - * @return string - */ - function _remove_invisible_characters($str) - { - static $non_displayables; - - if ( ! isset($non_displayables)) - { - // every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09), - $non_displayables = array( - '/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15 - '/%1[0-9a-f]/', // url encoded 16-31 - '/[\x00-\x08]/', // 00-08 - '/\x0b/', '/\x0c/', // 11, 12 - '/[\x0e-\x1f]/' // 14-31 - ); - } - - do - { - $cleaned = $str; - $str = preg_replace($non_displayables, '', $str); - } - while ($cleaned != $str); - - return $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 - * - * @access public - * @param type - * @return type - */ - function _compact_exploded_words($matches) - { - return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; - } - - // -------------------------------------------------------------------- - - /** - * Sanitize Naughty HTML - * - * Callback function for xss_clean() to remove naughty HTML elements - * - * @access private - * @param array - * @return string - */ - 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 - * - * @access private - * @param array - * @return string - */ - function _js_link_removal($match) - { - $attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1])); - return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])); - return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|', '<', '\\'), array('>', '<', '\\\\'), $match[0]); - } - - // -------------------------------------------------------------------- - - /** - * HTML Entity Decode Callback - * - * Used as a callback for XSS Clean - * - * @access public - * @param array - * @return string - */ - function _html_entity_decode_callback($match) - { - $CFG =& load_class('Config'); - $charset = $CFG->item('charset'); - - return $this->_html_entity_decode($match[0], strtoupper($charset)); - } - - // -------------------------------------------------------------------- - - /** - * HTML Entities Decode - * - * This function is a replacement for html_entity_decode() - * - * In some versions of PHP the native function does not work - * when UTF-8 is the specified character set, so this gives us - * a work-around. More info here: - * http://bugs.php.net/bug.php?id=25670 - * - * @access private - * @param string - * @param string - * @return string - */ - /* ------------------------------------------------- - /* Replacement for html_entity_decode() - /* -------------------------------------------------*/ - - /* - NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the - character set, and the PHP developers said they were not back porting the - fix to versions other than PHP 5.x. - */ - function _html_entity_decode($str, $charset='UTF-8') - { - if (stristr($str, '&') === FALSE) return $str; - - // 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. - - if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>='))) - { - $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); - } - - // Numeric Entities - $str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str); - $str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str); - - // Literal Entities - Slightly slow so we do another check - if (stristr($str, '&') === FALSE) - { - $str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES))); - } - - return $str; - } - - // -------------------------------------------------------------------- - - /** - * Filter Attributes - * - * Filters tag attributes for consistency and safety - * - * @access public - * @param string - * @return string - */ - 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; - } - - // -------------------------------------------------------------------- - -} -// END Input class - -/* End of file Input.php */ + '[removed]', + 'document.write' => '[removed]', + '.parentNode' => '[removed]', + '.innerHTML' => '[removed]', + 'window.location' => '[removed]', + '-moz-binding' => '[removed]', + '' => '-->', + ' '<![CDATA[' + ); + /* never allowed, regex replacement */ + var $never_allowed_regex = array( + "javascript\s*:" => '[removed]', + "expression\s*(\(|&\#40;)" => '[removed]', // CSS and IE + "vbscript\s*:" => '[removed]', // IE, surprise! + "Redirect\s+302" => '[removed]' + ); + + /** + * Constructor + * + * Sets whether to globally enable the XSS processing + * and whether to allow the $_GET array + * + * @access public + */ + function CI_Input() + { + log_message('debug', "Input Class Initialized"); + + $CFG =& load_class('Config'); + $this->use_xss_clean = ($CFG->item('global_xss_filtering') === TRUE) ? TRUE : FALSE; + $this->allow_get_array = ($CFG->item('enable_query_strings') === TRUE) ? TRUE : FALSE; + $this->_sanitize_globals(); + } + + // -------------------------------------------------------------------- + + /** + * 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() + { + // Would kind of 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 security. + // This is effectively the same as register_globals = off + foreach (array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES, $_ENV, (isset($_SESSION) && is_array($_SESSION)) ? $_SESSION : array()) as $global) + { + if ( ! is_array($global)) + { + if ( ! in_array($global, $protected)) + { + unset($GLOBALS[$global]); + } + } + else + { + foreach ($global as $key => $val) + { + if ( ! in_array($key, $protected)) + { + unset($GLOBALS[$key]); + } + + if (is_array($val)) + { + foreach($val as $k => $v) + { + if ( ! in_array($k, $protected)) + { + unset($GLOBALS[$k]); + } + } + } + } + } + } + + // Is $_GET data allowed? If not we'll set the $_GET to an empty array + if ($this->allow_get_array == FALSE) + { + $_GET = array(); + } + else + { + $_GET = $this->_clean_input_data($_GET); + } + + // Clean $_POST Data + $_POST = $this->_clean_input_data($_POST); + + // Clean $_COOKIE Data + // 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']); + $_COOKIE = $this->_clean_input_data($_COOKIE); + + 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 + if (get_magic_quotes_gpc()) + { + $str = stripslashes($str); + } + + // Should we filter the input data? + if ($this->use_xss_clean === TRUE) + { + $str = $this->xss_clean($str); + } + + // Standardize newlines + if (strpos($str, "\r") !== FALSE) + { + $str = str_replace(array("\r\n", "\r"), "\n", $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.'); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * 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->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 = '', $xss_clean = FALSE) + { + 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 = '', $xss_clean = FALSE) + { + 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); + } + + // -------------------------------------------------------------------- + + /** + * 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 + * + * @access public + * @return string + */ + function ip_address() + { + if ($this->ip_address !== FALSE) + { + return $this->ip_address; + } + + if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR')) + { + $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY); + $proxies = is_array($proxies) ? $proxies : array($proxies); + + $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']; + } + elseif ($this->server('REMOTE_ADDR') AND $this->server('HTTP_CLIENT_IP')) + { + $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; + } + elseif ($this->server('REMOTE_ADDR')) + { + $this->ip_address = $_SERVER['REMOTE_ADDR']; + } + elseif ($this->server('HTTP_CLIENT_IP')) + { + $this->ip_address = $_SERVER['HTTP_CLIENT_IP']; + } + elseif ($this->server('HTTP_X_FORWARDED_FOR')) + { + $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; + } + + if ($this->ip_address === FALSE) + { + $this->ip_address = '0.0.0.0'; + return $this->ip_address; + } + + if (strstr($this->ip_address, ',')) + { + $x = explode(',', $this->ip_address); + $this->ip_address = trim(end($x)); + } + + if ( ! $this->valid_ip($this->ip_address)) + { + $this->ip_address = '0.0.0.0'; + } + + return $this->ip_address; + } + + // -------------------------------------------------------------------- + + /** + * Validate IP Address + * + * Updated version suggested by Geert De Deckere + * + * @access public + * @param string + * @return string + */ + function valid_ip($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; + } + + // -------------------------------------------------------------------- + + /** + * 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; + } + + // -------------------------------------------------------------------- + + /** + * Filename Security + * + * @access public + * @param string + * @return string + */ + function filename_security($str) + { + $bad = array( + "../", + "./", + "", + "<", + ">", + "'", + '"', + '&', + '$', + '#', + '{', + '}', + '[', + ']', + '=', + ';', + '?', + "%20", + "%22", + "%3c", // < + "%253c", // < + "%3e", // > + "%0e", // > + "%28", // ( + "%29", // ) + "%2528", // ( + "%26", // & + "%24", // $ + "%3f", // ? + "%3b", // ; + "%3d" // = + ); + + return stripslashes(str_replace($bad, '', $str)); + } + + // -------------------------------------------------------------------- + + /** + * 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://blog.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 + * + * @access public + * @param string + * @return string + */ + 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 = $this->_remove_invisible_characters($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); + + /* + * 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, '_html_entity_decode_callback'), $str); + + /* + * Remove Invisible Characters Again! + */ + $str = $this->_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; + + /* + * Not Allowed Under Any Conditions + */ + + foreach ($this->never_allowed_str as $key => $val) + { + $str = str_replace($key, $val, $str); + } + + foreach ($this->never_allowed_regex as $key => $val) + { + $str = preg_replace("#".$key."#i", $val, $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', '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 JavaScript Event Handlers + * + * Note: This code is a little blunt. It removes + * the event handler and anything up to the closing >, + * but it's unlikely to be a problem. + * + */ + $event_handlers = array('[^a-z_\-]on\w*','xmlns'); + + if ($is_image === TRUE) + { + /* + * Adobe Photoshop puts XML metadata into JFIF images, including namespacing, + * so we have to allow this for images. -Paul + */ + unset($event_handlers[array_search('xmlns', $event_handlers)]); + } + + $str = preg_replace("#<([^><]+?)(".implode('|', $event_handlers).")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str); + + /* + * 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 + * + */ + foreach ($this->never_allowed_str as $key => $val) + { + $str = str_replace($key, $val, $str); + } + + foreach ($this->never_allowed_regex as $key => $val) + { + $str = preg_replace("#".$key."#i", $val, $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) + { + if ($str == $converted_string) + { + return TRUE; + } + else + { + return FALSE; + } + } + + log_message('debug', "XSS Filtering completed"); + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Random Hash for protecting URLs + * + * @access public + * @return string + */ + function xss_hash() + { + if ($this->xss_hash == '') + { + if (phpversion() >= 4.2) + mt_srand(); + else + mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff); + + $this->xss_hash = md5(time() + mt_rand(0, 1999999999)); + } + + return $this->xss_hash; + } + + // -------------------------------------------------------------------- + + /** + * Remove Invisible Characters + * + * This prevents sandwiching null characters + * between ascii characters, like Java\0script. + * + * @access public + * @param string + * @return string + */ + function _remove_invisible_characters($str) + { + static $non_displayables; + + if ( ! isset($non_displayables)) + { + // every control character except newline (dec 10), carriage return (dec 13), and horizontal tab (dec 09), + $non_displayables = array( + '/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15 + '/%1[0-9a-f]/', // url encoded 16-31 + '/[\x00-\x08]/', // 00-08 + '/\x0b/', '/\x0c/', // 11, 12 + '/[\x0e-\x1f]/' // 14-31 + ); + } + + do + { + $cleaned = $str; + $str = preg_replace($non_displayables, '', $str); + } + while ($cleaned != $str); + + return $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 + * + * @access public + * @param type + * @return type + */ + function _compact_exploded_words($matches) + { + return preg_replace('/\s+/s', '', $matches[1]).$matches[2]; + } + + // -------------------------------------------------------------------- + + /** + * Sanitize Naughty HTML + * + * Callback function for xss_clean() to remove naughty HTML elements + * + * @access private + * @param array + * @return string + */ + 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 + * + * @access private + * @param array + * @return string + */ + function _js_link_removal($match) + { + $attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1])); + return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|_filter_attributes(str_replace(array('<', '>'), '', $match[1])); + return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|', '<', '\\'), array('>', '<', '\\\\'), $match[0]); + } + + // -------------------------------------------------------------------- + + /** + * HTML Entity Decode Callback + * + * Used as a callback for XSS Clean + * + * @access public + * @param array + * @return string + */ + function _html_entity_decode_callback($match) + { + $CFG =& load_class('Config'); + $charset = $CFG->item('charset'); + + return $this->_html_entity_decode($match[0], strtoupper($charset)); + } + + // -------------------------------------------------------------------- + + /** + * HTML Entities Decode + * + * This function is a replacement for html_entity_decode() + * + * In some versions of PHP the native function does not work + * when UTF-8 is the specified character set, so this gives us + * a work-around. More info here: + * http://bugs.php.net/bug.php?id=25670 + * + * @access private + * @param string + * @param string + * @return string + */ + /* ------------------------------------------------- + /* Replacement for html_entity_decode() + /* -------------------------------------------------*/ + + /* + NOTE: html_entity_decode() has a bug in some PHP versions when UTF-8 is the + character set, and the PHP developers said they were not back porting the + fix to versions other than PHP 5.x. + */ + function _html_entity_decode($str, $charset='UTF-8') + { + if (stristr($str, '&') === FALSE) return $str; + + // 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. + + if (function_exists('html_entity_decode') && (strtolower($charset) != 'utf-8' OR version_compare(phpversion(), '5.0.0', '>='))) + { + $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); + } + + // Numeric Entities + $str = preg_replace('~&#x(0*[0-9a-f]{2,5});{0,1}~ei', 'chr(hexdec("\\1"))', $str); + $str = preg_replace('~&#([0-9]{2,4});{0,1}~e', 'chr(\\1)', $str); + + // Literal Entities - Slightly slow so we do another check + if (stristr($str, '&') === FALSE) + { + $str = strtr($str, array_flip(get_html_translation_table(HTML_ENTITIES))); + } + + return $str; + } + + // -------------------------------------------------------------------- + + /** + * Filter Attributes + * + * Filters tag attributes for consistency and safety + * + * @access public + * @param string + * @return string + */ + 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; + } + + // -------------------------------------------------------------------- + +} +// END Input class + +/* End of file Input.php */ /* Location: ./system/libraries/Input.php */ \ No newline at end of file diff --git a/system/libraries/Language.php b/system/libraries/Language.php index 515d04a..873dd85 100644 --- a/system/libraries/Language.php +++ b/system/libraries/Language.php @@ -1,123 +1,64 @@ -is_loaded, TRUE)) - { - return; - } - - if ($idiom == '') - { - $CI =& get_instance(); - $deft_lang = $CI->config->item('language'); - $idiom = ($deft_lang == '') ? 'english' : $deft_lang; - } - - // Determine where the language file is and load it - if (file_exists(APPPATH.'language/'.$idiom.'/'.$langfile)) - { - include(APPPATH.'language/'.$idiom.'/'.$langfile); - } - else - { - if (file_exists(BASEPATH.'language/'.$idiom.'/'.$langfile)) - { - include(BASEPATH.'language/'.$idiom.'/'.$langfile); - } - else - { - 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 = '') - { - $line = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line]; - return $line; - } - -} -// END Language Class - -/* End of file Language.php */ + 'unit', 'user_agent' => 'agent'); - - - /** - * Constructor - * - * Sets the path to the view files and gets the initial output buffering level - * - * @access public - */ - function CI_Loader() - { - $this->_ci_is_php5 = (floor(phpversion()) >= 5) ? TRUE : FALSE; - $this->_ci_view_path = APPPATH.'views/'; - $this->_ci_ob_level = ob_get_level(); - - log_message('debug', "Loader Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Class Loader - * - * This function lets users load and instantiate classes. - * It is designed to be called from a user's app controllers. - * - * @access public - * @param string the name of the class - * @param mixed the optional parameters - * @param string an optional object name - * @return void - */ - function library($library = '', $params = NULL, $object_name = NULL) - { - if ($library == '') - { - return FALSE; - } - - if ( ! is_null($params) AND ! is_array($params)) - { - $params = NULL; - } - - if (is_array($library)) - { - foreach ($library as $class) - { - $this->_ci_load_class($class, $params, $object_name); - } - } - else - { - $this->_ci_load_class($library, $params, $object_name); - } - - $this->_ci_assign_to_models(); - } - - // -------------------------------------------------------------------- - - /** - * Model Loader - * - * This function lets users load and instantiate models. - * - * @access public - * @param string the name of the class - * @param string name for the model - * @param bool database connection - * @return void - */ - function model($model, $name = '', $db_conn = FALSE) - { - if (is_array($model)) - { - foreach($model as $babe) - { - $this->model($babe); - } - return; - } - - if ($model == '') - { - return; - } - - // Is the model in a sub-folder? If so, parse out the filename and path. - if (strpos($model, '/') === FALSE) - { - $path = ''; - } - else - { - $x = explode('/', $model); - $model = end($x); - unset($x[count($x)-1]); - $path = implode('/', $x).'/'; - } - - 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); - - if ( ! file_exists(APPPATH.'models/'.$path.$model.EXT)) - { - show_error('Unable to locate the model you have specified: '.$model); - } - - 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('Model')) - { - load_class('Model', FALSE); - } - - require_once(APPPATH.'models/'.$path.$model.EXT); - - $model = ucfirst($model); - - $CI->$name = new $model(); - $CI->$name->_assign_libraries(); - - $this->_ci_models[] = $name; - } - - // -------------------------------------------------------------------- - - /** - * Database Loader - * - * @access public - * @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 - */ - function database($params = '', $return = FALSE, $active_record = FALSE) - { - // 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 == FALSE AND isset($CI->db) AND is_object($CI->db)) - { - return FALSE; - } - - require_once(BASEPATH.'database/DB'.EXT); - - 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); - - // Assign the DB object to any existing models - $this->_ci_assign_to_models(); - } - - // -------------------------------------------------------------------- - - /** - * Load the Utilities Class - * - * @access public - * @return string - */ - 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'.EXT); - require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility'.EXT); - $class = 'CI_DB_'.$CI->db->dbdriver.'_utility'; - - $CI->dbutil =& instantiate_class(new $class()); - - $CI->load->_ci_assign_to_models(); - } - - // -------------------------------------------------------------------- - - /** - * Load the Database Forge Class - * - * @access public - * @return string - */ - function dbforge() - { - if ( ! class_exists('CI_DB')) - { - $this->database(); - } - - $CI =& get_instance(); - - require_once(BASEPATH.'database/DB_forge'.EXT); - require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge'.EXT); - $class = 'CI_DB_'.$CI->db->dbdriver.'_forge'; - - $CI->dbforge = new $class(); - - $CI->load->_ci_assign_to_models(); - } - - // -------------------------------------------------------------------- - - /** - * 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. - * - * @access public - * @param string - * @param array - * @param bool - * @return void - */ - 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 - * - * @access public - * @param string - * @param bool - * @return string - */ - 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. - * - * @access public - * @param array - * @return void - */ - 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; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Load Helper - * - * This function loads the specified helper file. - * - * @access public - * @param mixed - * @return void - */ - function helper($helpers = array()) - { - if ( ! is_array($helpers)) - { - $helpers = array($helpers); - } - - foreach ($helpers as $helper) - { - $helper = strtolower(str_replace(EXT, '', str_replace('_helper', '', $helper)).'_helper'); - - if (isset($this->_ci_helpers[$helper])) - { - continue; - } - - $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.EXT; - - // Is this a helper extension request? - if (file_exists($ext_helper)) - { - $base_helper = BASEPATH.'helpers/'.$helper.EXT; - - if ( ! file_exists($base_helper)) - { - show_error('Unable to load the requested file: helpers/'.$helper.EXT); - } - - include_once($ext_helper); - include_once($base_helper); - } - elseif (file_exists(APPPATH.'helpers/'.$helper.EXT)) - { - include_once(APPPATH.'helpers/'.$helper.EXT); - } - else - { - if (file_exists(BASEPATH.'helpers/'.$helper.EXT)) - { - include_once(BASEPATH.'helpers/'.$helper.EXT); - } - else - { - show_error('Unable to load the requested file: helpers/'.$helper.EXT); - } - } - - $this->_ci_helpers[$helper] = TRUE; - log_message('debug', 'Helper loaded: '.$helper); - } - } - - // -------------------------------------------------------------------- - - /** - * Load Helpers - * - * This is simply an alias to the above function in case the - * user has written the plural form of this function. - * - * @access public - * @param array - * @return void - */ - function helpers($helpers = array()) - { - $this->helper($helpers); - } - - // -------------------------------------------------------------------- - - /** - * Load Plugin - * - * This function loads the specified plugin. - * - * @access public - * @param array - * @return void - */ - function plugin($plugins = array()) - { - if ( ! is_array($plugins)) - { - $plugins = array($plugins); - } - - foreach ($plugins as $plugin) - { - $plugin = strtolower(str_replace(EXT, '', str_replace('_pi', '', $plugin)).'_pi'); - - if (isset($this->_ci_plugins[$plugin])) - { - continue; - } - - if (file_exists(APPPATH.'plugins/'.$plugin.EXT)) - { - include_once(APPPATH.'plugins/'.$plugin.EXT); - } - else - { - if (file_exists(BASEPATH.'plugins/'.$plugin.EXT)) - { - include_once(BASEPATH.'plugins/'.$plugin.EXT); - } - else - { - show_error('Unable to load the requested file: plugins/'.$plugin.EXT); - } - } - - $this->_ci_plugins[$plugin] = TRUE; - log_message('debug', 'Plugin loaded: '.$plugin); - } - } - - // -------------------------------------------------------------------- - - /** - * Load Plugins - * - * This is simply an alias to the above function in case the - * user has written the plural form of this function. - * - * @access public - * @param array - * @return void - */ - function plugins($plugins = array()) - { - $this->plugin($plugins); - } - - // -------------------------------------------------------------------- - - /** - * Loads a language file - * - * @access public - * @param array - * @param string - * @return void - */ - 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 language files for scaffolding - * - * @access public - * @param string - * @return arra - */ - function scaffold_language($file = '', $lang = '', $return = FALSE) - { - $CI =& get_instance(); - return $CI->lang->load($file, $lang, $return); - } - - // -------------------------------------------------------------------- - - /** - * Loads a config file - * - * @access public - * @param string - * @return void - */ - function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) - { - $CI =& get_instance(); - $CI->config->load($file, $use_sections, $fail_gracefully); - } - - // -------------------------------------------------------------------- - - /** - * Scaffolding Loader - * - * This initializing function works a bit different than the - * others. It doesn't load the class. Instead, it simply - * sets a flag indicating that scaffolding is allowed to be - * used. The actual scaffolding function below is - * called by the front controller based on whether the - * second segment of the URL matches the "secret" scaffolding - * word stored in the application/config/routes.php - * - * @access public - * @param string - * @return void - */ - function scaffolding($table = '') - { - if ($table === FALSE) - { - show_error('You must include the name of the table you would like to access when you initialize scaffolding'); - } - - $CI =& get_instance(); - $CI->_ci_scaffolding = TRUE; - $CI->_ci_scaff_table = $table; - } - - // -------------------------------------------------------------------- - - /** - * 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 - * - * @access private - * @param array - * @return void - */ - 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]; - } - - // Set the path to the requested file - if ($_ci_path == '') - { - $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); - $_ci_file = ($_ci_ext == '') ? $_ci_view.EXT : $_ci_view; - $_ci_path = $this->_ci_view_path.$_ci_file; - } - else - { - $_ci_x = explode('/', $_ci_path); - $_ci_file = end($_ci_x); - } - - if ( ! 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. - // Only needed when running PHP 5 - - if ($this->_ci_is_instance()) - { - $_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 - { - // PHP 4 requires that we use a global - global $OUT; - $OUT->append_output(ob_get_contents()); - @ob_end_clean(); - } - } - - // -------------------------------------------------------------------- - - /** - * Load class - * - * This function loads the requested class. - * - * @access private - * @param string the item that is being loaded - * @param mixed any additional parameters - * @param string an optional object name - * @return void - */ - 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(EXT, '', trim($class, '/')); - - // Was the path included with the class name? - // We look for a slash to determine this - $subdir = ''; - if (strpos($class, '/') !== FALSE) - { - // explode the path so we can separate the filename from the path - $x = explode('/', $class); - - // Reset the $class variable now that we know the actual filename - $class = end($x); - - // Kill the filename from the array - unset($x[count($x)-1]); - - // Glue the path back together, sans filename - $subdir = implode($x, '/').'/'; - } - - // 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.EXT; - - // Is this a class extension request? - if (file_exists($subclass)) - { - $baseclass = BASEPATH.'libraries/'.ucfirst($class).EXT; - - 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; - for ($i = 1; $i < 3; $i++) - { - $path = ($i % 2) ? APPPATH : BASEPATH; - $filepath = $path.'libraries/'.$subdir.$class.EXT; - - // 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 - * - * @access private - * @param string - * @param string - * @param string an optional object name - * @return null - */ - function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) - { - // Is there an associated config file for this class? - if ($config === NULL) - { - // We test for both uppercase and lowercase, for servers that - // are case-sensitive with regard to file names - if (file_exists(APPPATH.'config/'.strtolower($class).EXT)) - { - include_once(APPPATH.'config/'.strtolower($class).EXT); - } - elseif (file_exists(APPPATH.'config/'.ucfirst(strtolower($class)).EXT)) - { - include_once(APPPATH.'config/'.ucfirst(strtolower($class)).EXT); - } - } - - 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, plugins, and helpers to be loaded automatically. - * - * @access private - * @param array - * @return void - */ - function _ci_autoloader() - { - include_once(APPPATH.'config/autoload'.EXT); - - if ( ! isset($autoload)) - { - return FALSE; - } - - // Load any custom config file - if (count($autoload['config']) > 0) - { - $CI =& get_instance(); - foreach ($autoload['config'] as $key => $val) - { - $CI->config->load($val); - } - } - - // Autoload plugins, helpers and languages - foreach (array('helper', 'plugin', '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'])) - { - $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 scaffolding - if (in_array('scaffolding', $autoload['libraries'])) - { - $this->scaffolding(); - $autoload['libraries'] = array_diff($autoload['libraries'], array('scaffolding')); - } - - // Load all other libraries - foreach ($autoload['libraries'] as $item) - { - $this->library($item); - } - } - - // Autoload models - if (isset($autoload['model'])) - { - $this->model($autoload['model']); - } - - } - - // -------------------------------------------------------------------- - - /** - * Assign to Models - * - * Makes sure that anything loaded by the loader class (libraries, plugins, etc.) - * will be available to models, if any exist. - * - * @access private - * @param object - * @return array - */ - function _ci_assign_to_models() - { - if (count($this->_ci_models) == 0) - { - return; - } - - if ($this->_ci_is_instance()) - { - $CI =& get_instance(); - foreach ($this->_ci_models as $model) - { - $CI->$model->_assign_libraries(); - } - } - else - { - foreach ($this->_ci_models as $model) - { - $this->$model->_assign_libraries(); - } - } - } - - // -------------------------------------------------------------------- - - /** - * Object to Array - * - * Takes an object as input and converts the class variables to array key/vals - * - * @access private - * @param object - * @return array - */ - function _ci_object_to_array($object) - { - return (is_object($object)) ? get_object_vars($object) : $object; - } - - // -------------------------------------------------------------------- - - /** - * Determines whether we should use the CI instance or $this - * - * @access private - * @return bool - */ - function _ci_is_instance() - { - if ($this->_ci_is_php5 == TRUE) - { - return TRUE; - } - - global $CI; - return (is_object($CI)) ? TRUE : FALSE; - } - -} - -/* End of file Loader.php */ + 'unit', 'user_agent' => 'agent'); + + + /** + * Constructor + * + * Sets the path to the view files and gets the initial output buffering level + * + * @access public + */ + function CI_Loader() + { + $this->_ci_is_php5 = (floor(phpversion()) >= 5) ? TRUE : FALSE; + $this->_ci_view_path = APPPATH.'views/'; + $this->_ci_ob_level = ob_get_level(); + + log_message('debug', "Loader Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Class Loader + * + * This function lets users load and instantiate classes. + * It is designed to be called from a user's app controllers. + * + * @access public + * @param string the name of the class + * @param mixed the optional parameters + * @param string an optional object name + * @return void + */ + function library($library = '', $params = NULL, $object_name = NULL) + { + if ($library == '') + { + return FALSE; + } + + if ( ! is_null($params) AND ! is_array($params)) + { + $params = NULL; + } + + if (is_array($library)) + { + foreach ($library as $class) + { + $this->_ci_load_class($class, $params, $object_name); + } + } + else + { + $this->_ci_load_class($library, $params, $object_name); + } + + $this->_ci_assign_to_models(); + } + + // -------------------------------------------------------------------- + + /** + * Model Loader + * + * This function lets users load and instantiate models. + * + * @access public + * @param string the name of the class + * @param string name for the model + * @param bool database connection + * @return void + */ + function model($model, $name = '', $db_conn = FALSE) + { + if (is_array($model)) + { + foreach($model as $babe) + { + $this->model($babe); + } + return; + } + + if ($model == '') + { + return; + } + + // Is the model in a sub-folder? If so, parse out the filename and path. + if (strpos($model, '/') === FALSE) + { + $path = ''; + } + else + { + $x = explode('/', $model); + $model = end($x); + unset($x[count($x)-1]); + $path = implode('/', $x).'/'; + } + + 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); + + if ( ! file_exists(APPPATH.'models/'.$path.$model.EXT)) + { + show_error('Unable to locate the model you have specified: '.$model); + } + + 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('Model')) + { + load_class('Model', FALSE); + } + + require_once(APPPATH.'models/'.$path.$model.EXT); + + $model = ucfirst($model); + + $CI->$name = new $model(); + $CI->$name->_assign_libraries(); + + $this->_ci_models[] = $name; + } + + // -------------------------------------------------------------------- + + /** + * Database Loader + * + * @access public + * @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 + */ + function database($params = '', $return = FALSE, $active_record = FALSE) + { + // 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 == FALSE AND isset($CI->db) AND is_object($CI->db)) + { + return FALSE; + } + + require_once(BASEPATH.'database/DB'.EXT); + + 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); + + // Assign the DB object to any existing models + $this->_ci_assign_to_models(); + } + + // -------------------------------------------------------------------- + + /** + * Load the Utilities Class + * + * @access public + * @return string + */ + 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'.EXT); + require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility'.EXT); + $class = 'CI_DB_'.$CI->db->dbdriver.'_utility'; + + $CI->dbutil =& instantiate_class(new $class()); + + $CI->load->_ci_assign_to_models(); + } + + // -------------------------------------------------------------------- + + /** + * Load the Database Forge Class + * + * @access public + * @return string + */ + function dbforge() + { + if ( ! class_exists('CI_DB')) + { + $this->database(); + } + + $CI =& get_instance(); + + require_once(BASEPATH.'database/DB_forge'.EXT); + require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge'.EXT); + $class = 'CI_DB_'.$CI->db->dbdriver.'_forge'; + + $CI->dbforge = new $class(); + + $CI->load->_ci_assign_to_models(); + } + + // -------------------------------------------------------------------- + + /** + * 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. + * + * @access public + * @param string + * @param array + * @param bool + * @return void + */ + 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 + * + * @access public + * @param string + * @param bool + * @return string + */ + 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. + * + * @access public + * @param array + * @return void + */ + 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; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Load Helper + * + * This function loads the specified helper file. + * + * @access public + * @param mixed + * @return void + */ + function helper($helpers = array()) + { + if ( ! is_array($helpers)) + { + $helpers = array($helpers); + } + + foreach ($helpers as $helper) + { + $helper = strtolower(str_replace(EXT, '', str_replace('_helper', '', $helper)).'_helper'); + + if (isset($this->_ci_helpers[$helper])) + { + continue; + } + + $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.EXT; + + // Is this a helper extension request? + if (file_exists($ext_helper)) + { + $base_helper = BASEPATH.'helpers/'.$helper.EXT; + + if ( ! file_exists($base_helper)) + { + show_error('Unable to load the requested file: helpers/'.$helper.EXT); + } + + include_once($ext_helper); + include_once($base_helper); + } + elseif (file_exists(APPPATH.'helpers/'.$helper.EXT)) + { + include_once(APPPATH.'helpers/'.$helper.EXT); + } + else + { + if (file_exists(BASEPATH.'helpers/'.$helper.EXT)) + { + include_once(BASEPATH.'helpers/'.$helper.EXT); + } + else + { + show_error('Unable to load the requested file: helpers/'.$helper.EXT); + } + } + + $this->_ci_helpers[$helper] = TRUE; + log_message('debug', 'Helper loaded: '.$helper); + } + } + + // -------------------------------------------------------------------- + + /** + * Load Helpers + * + * This is simply an alias to the above function in case the + * user has written the plural form of this function. + * + * @access public + * @param array + * @return void + */ + function helpers($helpers = array()) + { + $this->helper($helpers); + } + + // -------------------------------------------------------------------- + + /** + * Load Plugin + * + * This function loads the specified plugin. + * + * @access public + * @param array + * @return void + */ + function plugin($plugins = array()) + { + if ( ! is_array($plugins)) + { + $plugins = array($plugins); + } + + foreach ($plugins as $plugin) + { + $plugin = strtolower(str_replace(EXT, '', str_replace('_pi', '', $plugin)).'_pi'); + + if (isset($this->_ci_plugins[$plugin])) + { + continue; + } + + if (file_exists(APPPATH.'plugins/'.$plugin.EXT)) + { + include_once(APPPATH.'plugins/'.$plugin.EXT); + } + else + { + if (file_exists(BASEPATH.'plugins/'.$plugin.EXT)) + { + include_once(BASEPATH.'plugins/'.$plugin.EXT); + } + else + { + show_error('Unable to load the requested file: plugins/'.$plugin.EXT); + } + } + + $this->_ci_plugins[$plugin] = TRUE; + log_message('debug', 'Plugin loaded: '.$plugin); + } + } + + // -------------------------------------------------------------------- + + /** + * Load Plugins + * + * This is simply an alias to the above function in case the + * user has written the plural form of this function. + * + * @access public + * @param array + * @return void + */ + function plugins($plugins = array()) + { + $this->plugin($plugins); + } + + // -------------------------------------------------------------------- + + /** + * Loads a config file + * + * @access public + * @param string + * @return void + */ + function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE) + { + $CI =& get_instance(); + $CI->config->load($file, $use_sections, $fail_gracefully); + } + + // -------------------------------------------------------------------- + + /** + * Scaffolding Loader + * + * This initializing function works a bit different than the + * others. It doesn't load the class. Instead, it simply + * sets a flag indicating that scaffolding is allowed to be + * used. The actual scaffolding function below is + * called by the front controller based on whether the + * second segment of the URL matches the "secret" scaffolding + * word stored in the application/config/routes.php + * + * @access public + * @param string + * @return void + */ + function scaffolding($table = '') + { + if ($table === FALSE) + { + show_error('You must include the name of the table you would like to access when you initialize scaffolding'); + } + + $CI =& get_instance(); + $CI->_ci_scaffolding = TRUE; + $CI->_ci_scaff_table = $table; + } + + // -------------------------------------------------------------------- + + /** + * 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 + * + * @access private + * @param array + * @return void + */ + 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]; + } + + // Set the path to the requested file + if ($_ci_path == '') + { + $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION); + $_ci_file = ($_ci_ext == '') ? $_ci_view.EXT : $_ci_view; + $_ci_path = $this->_ci_view_path.$_ci_file; + } + else + { + $_ci_x = explode('/', $_ci_path); + $_ci_file = end($_ci_x); + } + + if ( ! 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. + // Only needed when running PHP 5 + + if ($this->_ci_is_instance()) + { + $_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 + { + // PHP 4 requires that we use a global + global $OUT; + $OUT->append_output(ob_get_contents()); + @ob_end_clean(); + } + } + + // -------------------------------------------------------------------- + + /** + * Load class + * + * This function loads the requested class. + * + * @access private + * @param string the item that is being loaded + * @param mixed any additional parameters + * @param string an optional object name + * @return void + */ + 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(EXT, '', trim($class, '/')); + + // Was the path included with the class name? + // We look for a slash to determine this + $subdir = ''; + if (strpos($class, '/') !== FALSE) + { + // explode the path so we can separate the filename from the path + $x = explode('/', $class); + + // Reset the $class variable now that we know the actual filename + $class = end($x); + + // Kill the filename from the array + unset($x[count($x)-1]); + + // Glue the path back together, sans filename + $subdir = implode($x, '/').'/'; + } + + // 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.EXT; + + // Is this a class extension request? + if (file_exists($subclass)) + { + $baseclass = BASEPATH.'libraries/'.ucfirst($class).EXT; + + 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; + for ($i = 1; $i < 3; $i++) + { + $path = ($i % 2) ? APPPATH : BASEPATH; + $filepath = $path.'libraries/'.$subdir.$class.EXT; + + // 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 + * + * @access private + * @param string + * @param string + * @param string an optional object name + * @return null + */ + function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL) + { + // Is there an associated config file for this class? + if ($config === NULL) + { + // We test for both uppercase and lowercase, for servers that + // are case-sensitive with regard to file names + if (file_exists(APPPATH.'config/'.strtolower($class).EXT)) + { + include_once(APPPATH.'config/'.strtolower($class).EXT); + } + elseif (file_exists(APPPATH.'config/'.ucfirst(strtolower($class)).EXT)) + { + include_once(APPPATH.'config/'.ucfirst(strtolower($class)).EXT); + } + } + + 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, plugins, and helpers to be loaded automatically. + * + * @access private + * @param array + * @return void + */ + function _ci_autoloader() + { + include_once(APPPATH.'config/autoload'.EXT); + + if ( ! isset($autoload)) + { + return FALSE; + } + + // Load any custom config file + if (count($autoload['config']) > 0) + { + $CI =& get_instance(); + foreach ($autoload['config'] as $key => $val) + { + $CI->config->load($val); + } + } + + // Autoload plugins, helpers + foreach (array('helper', 'plugin') 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'])) + { + $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 scaffolding + if (in_array('scaffolding', $autoload['libraries'])) + { + $this->scaffolding(); + $autoload['libraries'] = array_diff($autoload['libraries'], array('scaffolding')); + } + + // Load all other libraries + foreach ($autoload['libraries'] as $item) + { + $this->library($item); + } + } + + // Autoload models + if (isset($autoload['model'])) + { + $this->model($autoload['model']); + } + + } + + // -------------------------------------------------------------------- + + /** + * Assign to Models + * + * Makes sure that anything loaded by the loader class (libraries, plugins, etc.) + * will be available to models, if any exist. + * + * @access private + * @param object + * @return array + */ + function _ci_assign_to_models() + { + if (count($this->_ci_models) == 0) + { + return; + } + + if ($this->_ci_is_instance()) + { + $CI =& get_instance(); + foreach ($this->_ci_models as $model) + { + $CI->$model->_assign_libraries(); + } + } + else + { + foreach ($this->_ci_models as $model) + { + $this->$model->_assign_libraries(); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Object to Array + * + * Takes an object as input and converts the class variables to array key/vals + * + * @access private + * @param object + * @return array + */ + function _ci_object_to_array($object) + { + return (is_object($object)) ? get_object_vars($object) : $object; + } + + // -------------------------------------------------------------------- + + /** + * Determines whether we should use the CI instance or $this + * + * @access private + * @return bool + */ + function _ci_is_instance() + { + if ($this->_ci_is_php5 == TRUE) + { + return TRUE; + } + + global $CI; + return (is_object($CI)) ? TRUE : FALSE; + } + +} + +/* End of file Loader.php */ /* Location: ./system/libraries/Loader.php */ \ No newline at end of file diff --git a/system/libraries/Log.php b/system/libraries/Log.php index 99ed126..96325ac 100644 --- a/system/libraries/Log.php +++ b/system/libraries/Log.php @@ -1,117 +1,117 @@ - '1', 'DEBUG' => '2', 'INFO' => '3', 'ALL' => '4'); - - /** - * Constructor - * - * @access public - */ - function CI_Log() - { - $config =& get_config(); - - $this->log_path = ($config['log_path'] != '') ? $config['log_path'] : BASEPATH.'logs/'; - - if ( ! is_dir($this->log_path) OR ! is_really_writable($this->log_path)) - { - $this->_enabled = FALSE; - } - - if (is_numeric($config['log_threshold'])) - { - $this->_threshold = $config['log_threshold']; - } - - if ($config['log_date_format'] != '') - { - $this->_date_fmt = $config['log_date_format']; - } - } - - // -------------------------------------------------------------------- - - /** - * Write Log File - * - * Generally this function will be called using the global log_message() function - * - * @access public - * @param string the error level - * @param string the error message - * @param bool whether the error is a native PHP error - * @return bool - */ - function write_log($level = 'error', $msg, $php_error = FALSE) - { - if ($this->_enabled === FALSE) - { - return FALSE; - } - - $level = strtoupper($level); - - if ( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold)) - { - return FALSE; - } - - $filepath = $this->log_path.'log-'.date('Y-m-d').EXT; - $message = ''; - - if ( ! file_exists($filepath)) - { - $message .= "<"."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n"; - } - - if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE)) - { - return FALSE; - } - - $message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$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 */ + '1', 'DEBUG' => '2', 'INFO' => '3', 'ALL' => '4'); + + /** + * Constructor + * + * @access public + */ + function CI_Log() + { + $config =& get_config(); + + $this->log_path = ($config['log_path'] != '') ? $config['log_path'] : BASEPATH.'logs/'; + + if ( ! is_dir($this->log_path) OR ! is_really_writable($this->log_path)) + { + $this->_enabled = FALSE; + } + + if (is_numeric($config['log_threshold'])) + { + $this->_threshold = $config['log_threshold']; + } + + if ($config['log_date_format'] != '') + { + $this->_date_fmt = $config['log_date_format']; + } + } + + // -------------------------------------------------------------------- + + /** + * Write Log File + * + * Generally this function will be called using the global log_message() function + * + * @access public + * @param string the error level + * @param string the error message + * @param bool whether the error is a native PHP error + * @return bool + */ + function write_log($level = 'error', $msg, $php_error = FALSE) + { + if ($this->_enabled === FALSE) + { + return FALSE; + } + + $level = strtoupper($level); + + if ( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold)) + { + return FALSE; + } + + $filepath = $this->log_path.'log-'.date('Y-m-d').EXT; + $message = ''; + + if ( ! file_exists($filepath)) + { + $message .= "<"."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n"; + } + + if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE)) + { + return FALSE; + } + + $message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$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/Model.php b/system/libraries/Model.php index c2c5886..3b36438 100644 --- a/system/libraries/Model.php +++ b/system/libraries/Model.php @@ -1,83 +1,83 @@ -_assign_libraries( (method_exists($this, '__get') OR method_exists($this, '__set')) ? FALSE : TRUE ); - - // We don't want to assign the model object to itself when using the - // assign_libraries function below so we'll grab the name of the model parent - $this->_parent_name = ucfirst(get_class($this)); - - log_message('debug', "Model Class Initialized"); - } - - /** - * Assign Libraries - * - * Creates local references to all currently instantiated objects - * so that any syntax that can be legally used in a controller - * can be used within models. - * - * @access private - */ - function _assign_libraries($use_reference = TRUE) - { - $CI =& get_instance(); - foreach (array_keys(get_object_vars($CI)) as $key) - { - if ( ! isset($this->$key) AND $key != $this->_parent_name) - { - // In some cases using references can cause - // problems so we'll conditionally use them - if ($use_reference == TRUE) - { - $this->$key = NULL; // Needed to prevent reference errors with some configurations - $this->$key =& $CI->$key; - } - else - { - $this->$key = $CI->$key; - } - } - } - } - -} -// END Model Class - -/* End of file Model.php */ +_assign_libraries( (method_exists($this, '__get') OR method_exists($this, '__set')) ? FALSE : TRUE ); + + // We don't want to assign the model object to itself when using the + // assign_libraries function below so we'll grab the name of the model parent + $this->_parent_name = ucfirst(get_class($this)); + + log_message('debug', "Model Class Initialized"); + } + + /** + * Assign Libraries + * + * Creates local references to all currently instantiated objects + * so that any syntax that can be legally used in a controller + * can be used within models. + * + * @access private + */ + function _assign_libraries($use_reference = TRUE) + { + $CI =& get_instance(); + foreach (array_keys(get_object_vars($CI)) as $key) + { + if ( ! isset($this->$key) AND $key != $this->_parent_name) + { + // In some cases using references can cause + // problems so we'll conditionally use them + if ($use_reference == TRUE) + { + $this->$key = NULL; // Needed to prevent reference errors with some configurations + $this->$key =& $CI->$key; + } + else + { + $this->$key = $CI->$key; + } + } + } + } + +} +// END Model Class + +/* End of file Model.php */ /* Location: ./system/libraries/Model.php */ \ No newline at end of file diff --git a/system/libraries/Output.php b/system/libraries/Output.php index 06479cf..57c0bca 100644 --- a/system/libraries/Output.php +++ b/system/libraries/Output.php @@ -1,409 +1,409 @@ -final_output; - } - - // -------------------------------------------------------------------- - - /** - * Set Output - * - * Sets the output string - * - * @access public - * @param string - * @return void - */ - function set_output($output) - { - $this->final_output = $output; - } - - // -------------------------------------------------------------------- - - /** - * 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; - } - } - - // -------------------------------------------------------------------- - - /** - * 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 - * @return void - */ - function set_header($header, $replace = TRUE) - { - $this->headers[] = array($header, $replace); - } - - // -------------------------------------------------------------------- - - /** - * 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); - } - - // -------------------------------------------------------------------- - - /** - * Enable/disable Profiler - * - * @access public - * @param bool - * @return void - */ - function enable_profiler($val = TRUE) - { - $this->enable_profiler = (is_bool($val)) ? $val : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Set Cache - * - * @access public - * @param integer - * @return void - */ - function cache($time) - { - $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time; - } - - // -------------------------------------------------------------------- - - /** - * 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 - * @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; - - // -------------------------------------------------------------------- - - // Set the output data - if ($output == '') - { - $output =& $this->final_output; - } - - // -------------------------------------------------------------------- - - // Do we need to write a cache file? - if ($this->cache_expiration > 0) - { - $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'); - $output = str_replace('{elapsed_time}', $elapsed, $output); - - $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; - $output = str_replace('{memory_usage}', $memory, $output); - - // -------------------------------------------------------------------- - - // Is compression requested? - if ($CFG->item('compress_output') === TRUE) - { - 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 get_instance() function exist? - // If not we know we are dealing with a cache file so we'll - // simply echo out the data and exit. - if ( ! function_exists('get_instance')) - { - echo $output; - log_message('debug', "Final output sent to browser"); - log_message('debug', "Total execution time: ".$elapsed); - return TRUE; - } - - // -------------------------------------------------------------------- - - // Grab the super object. We'll need it in a moment... - $CI =& get_instance(); - - // 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 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 - * @return void - */ - function _write_cache($output) - { - $CI =& get_instance(); - $path = $CI->config->item('cache_path'); - - $cache_path = ($path == '') ? BASEPATH.'cache/' : $path; - - if ( ! is_dir($cache_path) OR ! is_really_writable($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, DIR_WRITE_MODE); - - log_message('debug', "Cache file written: ".$cache_path); - } - - // -------------------------------------------------------------------- - - /** - * Update/serve a cached file - * - * @access public - * @return void - */ - function _display_cache(&$CFG, &$URI) - { - $cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path'); - - if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) - { - return FALSE; - } - - // 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']))) - { - @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 */ +final_output; + } + + // -------------------------------------------------------------------- + + /** + * Set Output + * + * Sets the output string + * + * @access public + * @param string + * @return void + */ + function set_output($output) + { + $this->final_output = $output; + } + + // -------------------------------------------------------------------- + + /** + * 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; + } + } + + // -------------------------------------------------------------------- + + /** + * 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 + * @return void + */ + function set_header($header, $replace = TRUE) + { + $this->headers[] = array($header, $replace); + } + + // -------------------------------------------------------------------- + + /** + * 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); + } + + // -------------------------------------------------------------------- + + /** + * Enable/disable Profiler + * + * @access public + * @param bool + * @return void + */ + function enable_profiler($val = TRUE) + { + $this->enable_profiler = (is_bool($val)) ? $val : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Set Cache + * + * @access public + * @param integer + * @return void + */ + function cache($time) + { + $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time; + } + + // -------------------------------------------------------------------- + + /** + * 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 + * @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; + + // -------------------------------------------------------------------- + + // Set the output data + if ($output == '') + { + $output =& $this->final_output; + } + + // -------------------------------------------------------------------- + + // Do we need to write a cache file? + if ($this->cache_expiration > 0) + { + $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'); + $output = str_replace('{elapsed_time}', $elapsed, $output); + + $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB'; + $output = str_replace('{memory_usage}', $memory, $output); + + // -------------------------------------------------------------------- + + // Is compression requested? + if ($CFG->item('compress_output') === TRUE) + { + 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 get_instance() function exist? + // If not we know we are dealing with a cache file so we'll + // simply echo out the data and exit. + if ( ! function_exists('get_instance')) + { + echo $output; + log_message('debug', "Final output sent to browser"); + log_message('debug', "Total execution time: ".$elapsed); + return TRUE; + } + + // -------------------------------------------------------------------- + + // Grab the super object. We'll need it in a moment... + $CI =& get_instance(); + + // 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 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 + * @return void + */ + function _write_cache($output) + { + $CI =& get_instance(); + $path = $CI->config->item('cache_path'); + + $cache_path = ($path == '') ? BASEPATH.'cache/' : $path; + + if ( ! is_dir($cache_path) OR ! is_really_writable($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, DIR_WRITE_MODE); + + log_message('debug', "Cache file written: ".$cache_path); + } + + // -------------------------------------------------------------------- + + /** + * Update/serve a cached file + * + * @access public + * @return void + */ + function _display_cache(&$CFG, &$URI) + { + $cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path'); + + if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path)) + { + return FALSE; + } + + // 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']))) + { + @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/libraries/Output.php */ \ No newline at end of file diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index d6321f4..5c77aab 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -1,244 +1,244 @@ -'; - 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'; - - /** - * Constructor - * - * @access public - * @param array initialization parameters - */ - function CI_Pagination($params = array()) - { - if (count($params) > 0) - { - $this->initialize($params); - } - - 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 ''; - } - - // 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) != 0) - { - $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) != 0) - { - $this->cur_page = $CI->uri->segment($this->uri_segment); - - // Prep the current page - no funny business! - $this->cur_page = (int) $this->cur_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 = 0; - } - - // Is the page number beyond the result range? - // If so we show the last page - if ($this->cur_page > $this->total_rows) - { - $this->cur_page = ($num_pages - 1) * $this->per_page; - } - - $uri_page_number = $this->cur_page; - $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->cur_page > ($this->num_links + 1)) - { - $output .= $this->first_tag_open.''.$this->first_link.''.$this->first_tag_close; - } - - // Render the "previous" link - if ($this->cur_page != 1) - { - $i = $uri_page_number - $this->per_page; - if ($i == 0) $i = ''; - $output .= $this->prev_tag_open.''.$this->prev_link.''.$this->prev_tag_close; - } - - // Write the digit links - for ($loop = $start -1; $loop <= $end; $loop++) - { - $i = ($loop * $this->per_page) - $this->per_page; - - if ($i >= 0) - { - if ($this->cur_page == $loop) - { - $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page - } - else - { - $n = ($i == 0) ? '' : $i; - $output .= $this->num_tag_open.''.$loop.''.$this->num_tag_close; - } - } - } - - // Render the "next" link - if ($this->cur_page < $num_pages) - { - $output .= $this->next_tag_open.''.$this->next_link.''.$this->next_tag_close; - } - - // Render the "Last" link - if (($this->cur_page + $this->num_links) < $num_pages) - { - $i = (($num_pages * $this->per_page) - $this->per_page); - $output .= $this->last_tag_open.''.$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 */ +'; + 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'; + + /** + * Constructor + * + * @access public + * @param array initialization parameters + */ + function CI_Pagination($params = array()) + { + if (count($params) > 0) + { + $this->initialize($params); + } + + 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 ''; + } + + // 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) != 0) + { + $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) != 0) + { + $this->cur_page = $CI->uri->segment($this->uri_segment); + + // Prep the current page - no funny business! + $this->cur_page = (int) $this->cur_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 = 0; + } + + // Is the page number beyond the result range? + // If so we show the last page + if ($this->cur_page > $this->total_rows) + { + $this->cur_page = ($num_pages - 1) * $this->per_page; + } + + $uri_page_number = $this->cur_page; + $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->cur_page > ($this->num_links + 1)) + { + $output .= $this->first_tag_open.''.$this->first_link.''.$this->first_tag_close; + } + + // Render the "previous" link + if ($this->cur_page != 1) + { + $i = $uri_page_number - $this->per_page; + if ($i == 0) $i = ''; + $output .= $this->prev_tag_open.''.$this->prev_link.''.$this->prev_tag_close; + } + + // Write the digit links + for ($loop = $start -1; $loop <= $end; $loop++) + { + $i = ($loop * $this->per_page) - $this->per_page; + + if ($i >= 0) + { + if ($this->cur_page == $loop) + { + $output .= $this->cur_tag_open.$loop.$this->cur_tag_close; // Current page + } + else + { + $n = ($i == 0) ? '' : $i; + $output .= $this->num_tag_open.''.$loop.''.$this->num_tag_close; + } + } + } + + // Render the "next" link + if ($this->cur_page < $num_pages) + { + $output .= $this->next_tag_open.''.$this->next_link.''.$this->next_tag_close; + } + + // Render the "Last" link + if (($this->cur_page + $this->num_links) < $num_pages) + { + $i = (($num_pages * $this->per_page) - $this->per_page); + $output .= $this->last_tag_open.''.$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 index da8b8bc..6e5890b 100644 --- a/system/libraries/Parser.php +++ b/system/libraries/Parser.php @@ -1,173 +1,173 @@ -load->view($template, $data, TRUE); - - 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->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("|".$this->l_delim . $variable . $this->r_delim."(.+?)".$this->l_delim . '/' . $variable . $this->r_delim."|s", $string, $match)) - { - return FALSE; - } - - return $match; - } - -} -// END Parser Class - -/* End of file Parser.php */ +load->view($template, $data, TRUE); + + 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->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("|".$this->l_delim . $variable . $this->r_delim."(.+?)".$this->l_delim . '/' . $variable . $this->r_delim."|s", $string, $match)) + { + return FALSE; + } + + return $match; + } + +} +// END Parser Class + +/* End of file Parser.php */ /* Location: ./system/libraries/Parser.php */ \ No newline at end of file diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php index 336745f..f6def38 100644 --- a/system/libraries/Profiler.php +++ b/system/libraries/Profiler.php @@ -1,392 +1,391 @@ -CI =& get_instance(); - $this->CI->load->language('profiler'); - } - - // -------------------------------------------------------------------- - - /** - * 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 - * - * @access private - * @return array - */ - 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 - * - * @access private - * @return string - */ - 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"; - - foreach ($dbs as $db) - { - $output .= '
      '; - $output .= "\n"; - $output .= '  '.$this->CI->lang->line('profiler_database').':  '.$db->database.'   '.$this->CI->lang->line('profiler_queries').': '.count($this->CI->db->queries).'   '; - $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 - * - * @access private - * @return string - */ - 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 - * - * @access private - * @return string - */ - 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 - * - * @access private - * @return string - */ - 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 - * - * @access private - * @return string - */ - 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 - * - * @access public - * @return string - */ - 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_usage')."
      "; - } - - $output .= "
      "; - - return $output; - } - - // -------------------------------------------------------------------- - - /** - * Run the Profiler - * - * @access private - * @return string - */ - function run() - { - $output = "
      "; - - $output .= $this->_compile_uri_string(); - $output .= $this->_compile_controller_info(); - $output .= $this->_compile_memory_usage(); - $output .= $this->_compile_benchmarks(); - $output .= $this->_compile_get(); - $output .= $this->_compile_post(); - $output .= $this->_compile_queries(); - - $output .= '
      '; - - return $output; - } - -} - -// END CI_Profiler class - -/* End of file Profiler.php */ +CI =& get_instance(); + } + + // -------------------------------------------------------------------- + + /** + * 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 + * + * @access private + * @return array + */ + 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 .= '  '.T_('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 + * + * @access private + * @return string + */ + 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 .= '  '.T_('profiler_queries').'  '; + $output .= "\n"; + $output .= "\n\n\n"; + $output .="\n"; + $output .= "
      ".T_('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"; + + foreach ($dbs as $db) + { + $output .= '
      '; + $output .= "\n"; + $output .= '  '.T_('profiler_database').':  '.$db->database.'   '.T_('profiler_queries').': '.count($this->CI->db->queries).'   '; + $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 .= "
      ".T_('profiler_no_queries')."
      ".$time."  ".$val."
      \n"; + $output .= "
      "; + + } + + return $output; + } + + + // -------------------------------------------------------------------- + + /** + * Compile $_GET Data + * + * @access private + * @return string + */ + function _compile_get() + { + $output = "\n\n"; + $output .= '
      '; + $output .= "\n"; + $output .= '  '.T_('profiler_get_data').'  '; + $output .= "\n"; + + if (count($_GET) == 0) + { + $output .= "
      ".T_('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 + * + * @access private + * @return string + */ + function _compile_post() + { + $output = "\n\n"; + $output .= '
      '; + $output .= "\n"; + $output .= '  '.T_('profiler_post_data').'  '; + $output .= "\n"; + + if (count($_POST) == 0) + { + $output .= "
      ".T_('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 + * + * @access private + * @return string + */ + function _compile_uri_string() + { + $output = "\n\n"; + $output .= '
      '; + $output .= "\n"; + $output .= '  '.T_('profiler_uri_string').'  '; + $output .= "\n"; + + if ($this->CI->uri->uri_string == '') + { + $output .= "
      ".T_('profiler_no_uri')."
      "; + } + else + { + $output .= "
      ".$this->CI->uri->uri_string."
      "; + } + + $output .= "
      "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Show the controller and function that were called + * + * @access private + * @return string + */ + function _compile_controller_info() + { + $output = "\n\n"; + $output .= '
      '; + $output .= "\n"; + $output .= '  '.T_('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 + * + * @access public + * @return string + */ + function _compile_memory_usage() + { + $output = "\n\n"; + $output .= '
      '; + $output .= "\n"; + $output .= '  '.T_('profiler_memory_usage').'  '; + $output .= "\n"; + + if (function_exists('memory_get_usage') && ($usage = memory_get_usage()) != '') + { + $output .= "
      ".number_format($usage).' bytes
      '; + } + else + { + $output .= "
      ".T_('profiler_no_memory_usage')."
      "; + } + + $output .= "
      "; + + return $output; + } + + // -------------------------------------------------------------------- + + /** + * Run the Profiler + * + * @access private + * @return string + */ + function run() + { + $output = "
      "; + + $output .= $this->_compile_uri_string(); + $output .= $this->_compile_controller_info(); + $output .= $this->_compile_memory_usage(); + $output .= $this->_compile_benchmarks(); + $output .= $this->_compile_get(); + $output .= $this->_compile_post(); + $output .= $this->_compile_queries(); + + $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/Router.php b/system/libraries/Router.php index b7d4c49..4914a90 100644 --- a/system/libraries/Router.php +++ b/system/libraries/Router.php @@ -1,389 +1,389 @@ -config =& load_class('Config'); - $this->uri =& load_class('URI'); - $this->_set_routing(); - 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? - // If so, we're done since segment based URIs are not used with query strings. - if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')])) - { - $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); - - if (isset($_GET[$this->config->item('function_trigger')])) - { - $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')]))); - } - - return; - } - - // Load the routes.php file. - @include(APPPATH.'config/routes'.EXT); - $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']); - - // 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 == '') - { - 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."); - } - - if (strpos($this->default_controller, '/') !== FALSE) - { - $x = explode('/', $this->default_controller); - - $this->set_class(end($x)); - $this->set_method('index'); - $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."); - return; - } - unset($this->routes['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 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_class($segments[0]); - - if (isset($segments[1])) - { - // A scaffolding request. No funny business with the URL - if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding') - { - $this->scaffolding_request = TRUE; - unset($this->routes['scaffolding_trigger']); - } - else - { - // 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) - { - // Does the requested controller exist in the root folder? - if (file_exists(APPPATH.'controllers/'.$segments[0].EXT)) - { - 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].EXT)) - { - show_404($this->fetch_directory().$segments[0]); - } - } - 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.EXT)) - { - $this->directory = ''; - return array(); - } - - } - - return $segments; - } - - // Can't find the requested controller... - 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() - { - // Do we even have any custom routing to deal with? - // There is a default scaffolding trigger, so we'll look just for 1 - if (count($this->routes) == 1) - { - $this->_set_request($this->uri->segments); - return; - } - - // 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])) - { - $this->_set_request(explode('/', $this->routes[$uri])); - return; - } - - // 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); - } - - $this->_set_request(explode('/', $val)); - return; - } - } - - // 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; - } - -} -// END Router Class - -/* End of file Router.php */ +config =& load_class('Config'); + $this->uri =& load_class('URI'); + $this->_set_routing(); + 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? + // If so, we're done since segment based URIs are not used with query strings. + if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')])) + { + $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')]))); + + if (isset($_GET[$this->config->item('function_trigger')])) + { + $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')]))); + } + + return; + } + + // Load the routes.php file. + @include(APPPATH.'config/routes'.EXT); + $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']); + + // 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 == '') + { + 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."); + } + + if (strpos($this->default_controller, '/') !== FALSE) + { + $x = explode('/', $this->default_controller); + + $this->set_class(end($x)); + $this->set_method('index'); + $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."); + return; + } + unset($this->routes['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 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_class($segments[0]); + + if (isset($segments[1])) + { + // A scaffolding request. No funny business with the URL + if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding') + { + $this->scaffolding_request = TRUE; + unset($this->routes['scaffolding_trigger']); + } + else + { + // 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) + { + // Does the requested controller exist in the root folder? + if (file_exists(APPPATH.'controllers/'.$segments[0].EXT)) + { + 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].EXT)) + { + show_404($this->fetch_directory().$segments[0]); + } + } + 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.EXT)) + { + $this->directory = ''; + return array(); + } + + } + + return $segments; + } + + // Can't find the requested controller... + 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() + { + // Do we even have any custom routing to deal with? + // There is a default scaffolding trigger, so we'll look just for 1 + if (count($this->routes) == 1) + { + $this->_set_request($this->uri->segments); + return; + } + + // 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])) + { + $this->_set_request(explode('/', $this->routes[$uri])); + return; + } + + // 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); + } + + $this->_set_request(explode('/', $val)); + return; + } + } + + // 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; + } + +} +// END Router Class + +/* End of file Router.php */ /* Location: ./system/libraries/Router.php */ \ No newline at end of file diff --git a/system/libraries/Session.php b/system/libraries/Session.php index b17a133..c585583 100644 --- a/system/libraries/Session.php +++ b/system/libraries/Session.php @@ -1,758 +1,758 @@ -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_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) - { - $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key); - } - - // 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, 50))) - { - $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, 50), - 'last_activity' => $this->now - ); - - - // 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 AND 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 - ); - } - - // -------------------------------------------------------------------- - - /** - * 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 mixed - */ - function all_userdata() - { - return ( ! isset($this->userdata)) ? FALSE : $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); - } - - // Set the cookie - setcookie( - $this->sess_cookie_name, - $cookie_data, - $this->sess_expiration + time(), - $this->cookie_path, - $this->cookie_domain, - 0 - ); - } - - // -------------------------------------------------------------------- - - /** - * 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) - { - $data[$key] = str_replace('\\', '{{slash}}', $val); - } - } - else - { - $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) - { - $data[$key] = str_replace('{{slash}}', '\\', $val); - } - - return $data; - } - - return str_replace('{{slash}}', '\\', $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 */ +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_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) + { + $this->$key = (isset($params[$key])) ? $params[$key] : $this->CI->config->item($key); + } + + // 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, 50))) + { + $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, 50), + 'last_activity' => $this->now + ); + + + // 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 AND 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 + ); + } + + // -------------------------------------------------------------------- + + /** + * 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 mixed + */ + function all_userdata() + { + return ( ! isset($this->userdata)) ? FALSE : $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); + } + + // Set the cookie + setcookie( + $this->sess_cookie_name, + $cookie_data, + $this->sess_expiration + time(), + $this->cookie_path, + $this->cookie_domain, + 0 + ); + } + + // -------------------------------------------------------------------- + + /** + * 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) + { + $data[$key] = str_replace('\\', '{{slash}}', $val); + } + } + else + { + $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) + { + $data[$key] = str_replace('{{slash}}', '\\', $val); + } + + return $data; + } + + return str_replace('{{slash}}', '\\', $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 index ff7e720..48b765b 100644 --- a/system/libraries/Sha1.php +++ b/system/libraries/Sha1.php @@ -1,251 +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 */ +> 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 index 18b2fda..e5494c1 100644 --- a/system/libraries/Table.php +++ b/system/libraries/Table.php @@ -1,440 +1,440 @@ -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 = (is_array($args[0])) ? $args[0] : $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[] = (is_array($args[0])) ? $args[0] : $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(); - - - // Build the table! - - $out = $this->template['table_open']; - $out .= $this->newline; - - // Add any caption here - if ($this->caption) - { - $out .= $this->newline; - $out .= '
      ' . $this->caption . '
      ', - - 'heading_row_start' => '', - 'heading_row_end' => '', - 'heading_cell_start' => '', - - '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 */ +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 = (is_array($args[0])) ? $args[0] : $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[] = (is_array($args[0])) ? $args[0] : $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(); + + + // Build the table! + + $out = $this->template['table_open']; + $out .= $this->newline; + + // Add any caption here + if ($this->caption) + { + $out .= $this->newline; + $out .= '

    ' . $this->caption . '
    ', + + 'heading_row_start' => '', + 'heading_row_end' => '', + 'heading_cell_start' => '', + + '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 index af2fb7e..35760e6 100644 --- a/system/libraries/Trackback.php +++ b/system/libraries/Trackback.php @@ -1,547 +1,547 @@ - '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); - var $convert_ascii = TRUE; - var $response = ''; - var $error_msg = array(); - - /** - * Constructor - * - * @access public - */ - function CI_Trackback() - { - 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 (strstr($url, '?')) - { - $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 */ + '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); + var $convert_ascii = TRUE; + var $response = ''; + var $error_msg = array(); + + /** + * Constructor + * + * @access public + */ + function CI_Trackback() + { + 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 (strstr($url, '?')) + { + $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 index 3186f7e..e951bd4 100644 --- a/system/libraries/Typography.php +++ b/system/libraries/Typography.php @@ -1,406 +1,406 @@ - 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; - - /** - * Nothing to do here... - * - */ - function CI_Typography() - { - } - - /** - * 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 - * - * @access public - * @param string - * @return string - */ - 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. - * - * @access public - * @return void - */ - function do_xss_clean() - { - $file = $this->upload_path.$this->file_name; - - if (filesize($file) == 0) - { - return FALSE; - } - - if (($data = @file_get_contents($file)) === FALSE) - { - return FALSE; - } - - if ( ! $fp = @fopen($file, FOPEN_READ_WRITE)) - { - return FALSE; - } - - $CI =& get_instance(); - $data = $CI->input->xss_clean($data); - - flock($fp, LOCK_EX); - fwrite($fp, $data); - flock($fp, LOCK_UN); - fclose($fp); - } - - // -------------------------------------------------------------------- - - /** - * Set an error message - * - * @access public - * @param string - * @return void - */ - 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 - * - * @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; - } - - // -------------------------------------------------------------------- - - /** - * List of Mime Types - * - * This is a list of mime types. We use it to validate - * the "allowed types" set by the developer - * - * @access public - * @param string - * @return string - */ - function mimes_types($mime) - { - global $mimes; - - if (count($this->mimes) == 0) - { - if (@require_once(APPPATH.'config/mimes'.EXT)) - { - $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 - * - * @access private - * @param string - * @return string - */ - function _prep_filename($filename) - { - if (strpos($filename, '.') === FALSE) - { - 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; - } - - // -------------------------------------------------------------------- - -} -// END Upload Class - -/* End of file Upload.php */ + 0) + { + $this->initialize($props); + } + + log_message('debug', "Upload Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Initialize preferences + * + * @access public + * @param array + * @return void + */ + function initialize($config = array()) + { + $defaults = array( + 'max_size' => 0, + 'max_width' => 0, + 'max_height' => 0, + 'max_filename' => 0, + 'allowed_types' => "", + 'file_temp' => "", + 'file_name' => "", + 'orig_name' => "", + 'file_type' => "", + 'file_size' => "", + 'file_ext' => "", + 'upload_path' => "", + 'overwrite' => FALSE, + 'encrypt_name' => FALSE, + 'is_image' => FALSE, + 'image_width' => '', + 'image_height' => '', + 'image_type' => '', + 'image_size_str' => '', + 'error_msg' => array(), + 'mimes' => array(), + 'remove_spaces' => TRUE, + 'xss_clean' => FALSE, + 'temp_prefix' => "temp_file_", + 'client_name' => '' + ); + + + foreach ($defaults as $key => $val) + { + if (isset($config[$key])) + { + $method = 'set_'.$key; + if (method_exists($this, $method)) + { + $this->$method($config[$key]); + } + else + { + $this->$key = $config[$key]; + } + } + else + { + $this->$key = $val; + } + } + + // if a file_name was provided in the config, use it instead of the user input + // supplied file name for all uploads until initialized again + $this->_file_name_override = $this->file_name; + } + + // -------------------------------------------------------------------- + + /** + * Perform the file upload + * + * @access public + * @return bool + */ + function do_upload($field = 'userfile') + { + // Is $_FILES[$field] set? If not, no reason to continue. + if ( ! isset($_FILES[$field])) + { + $this->set_error('upload_no_file_selected'); + return FALSE; + } + + // Is the upload path valid? + if ( ! $this->validate_upload_path()) + { + // errors will already be set by validate_upload_path() so just return FALSE + return FALSE; + } + + // Was the file able to be uploaded? If not, determine the reason why. + if ( ! is_uploaded_file($_FILES[$field]['tmp_name'])) + { + $error = ( ! isset($_FILES[$field]['error'])) ? 4 : $_FILES[$field]['error']; + + switch($error) + { + case 1: // UPLOAD_ERR_INI_SIZE + $this->set_error('upload_file_exceeds_limit'); + break; + case 2: // UPLOAD_ERR_FORM_SIZE + $this->set_error('upload_file_exceeds_form_limit'); + break; + case 3: // UPLOAD_ERR_PARTIAL + $this->set_error('upload_file_partial'); + break; + case 4: // UPLOAD_ERR_NO_FILE + $this->set_error('upload_no_file_selected'); + break; + case 6: // UPLOAD_ERR_NO_TMP_DIR + $this->set_error('upload_no_temp_directory'); + break; + case 7: // UPLOAD_ERR_CANT_WRITE + $this->set_error('upload_unable_to_write_file'); + break; + case 8: // UPLOAD_ERR_EXTENSION + $this->set_error('upload_stopped_by_extension'); + break; + default : $this->set_error('upload_no_file_selected'); + break; + } + + return FALSE; + } + + // Set the uploaded data as class variables + $this->file_temp = $_FILES[$field]['tmp_name']; + $this->file_size = $_FILES[$field]['size']; + $this->file_type = preg_replace("/^(.+?);.*$/", "\\1", $_FILES[$field]['type']); + $this->file_type = strtolower(trim(stripslashes($this->file_type), '"')); + $this->file_name = $this->_prep_filename($_FILES[$field]['name']); + $this->file_ext = $this->get_extension($this->file_name); + $this->client_name = $this->file_name; + + // Is the file type allowed to be uploaded? + if ( ! $this->is_allowed_filetype()) + { + $this->set_error('upload_invalid_filetype'); + return FALSE; + } + + // if we're overriding, let's now make sure the new name and type is allowed + if ($this->_file_name_override != '') + { + $this->file_name = $this->_prep_filename($this->_file_name_override); + $this->file_ext = $this->get_extension($this->file_name); + + if ( ! $this->is_allowed_filetype(TRUE)) + { + $this->set_error('upload_invalid_filetype'); + return FALSE; + } + } + + // Convert the file size to kilobytes + if ($this->file_size > 0) + { + $this->file_size = round($this->file_size/1024, 2); + } + + // Is the file size within the allowed maximum? + if ( ! $this->is_allowed_filesize()) + { + $this->set_error('upload_invalid_filesize'); + return FALSE; + } + + // Are the image dimensions within the allowed size? + // Note: This can fail if the server has an open_basdir restriction. + if ( ! $this->is_allowed_dimensions()) + { + $this->set_error('upload_invalid_dimensions'); + return FALSE; + } + + // Sanitize the file name for security + $this->file_name = $this->clean_file_name($this->file_name); + + // Truncate the file name if it's too long + if ($this->max_filename > 0) + { + $this->file_name = $this->limit_filename_length($this->file_name, $this->max_filename); + } + + // Remove white spaces in the name + if ($this->remove_spaces == TRUE) + { + $this->file_name = preg_replace("/\s+/", "_", $this->file_name); + } + + /* + * Validate the file name + * This function appends an number onto the end of + * the file if one with the same name already exists. + * If it returns false there was a problem. + */ + $this->orig_name = $this->file_name; + + if ($this->overwrite == FALSE) + { + $this->file_name = $this->set_filename($this->upload_path, $this->file_name); + + if ($this->file_name === FALSE) + { + return FALSE; + } + } + + /* + * Move the file to the final destination + * To deal with different server configurations + * we'll attempt to use copy() first. If that fails + * we'll use move_uploaded_file(). One of the two should + * reliably work in most environments + */ + if ( ! @copy($this->file_temp, $this->upload_path.$this->file_name)) + { + if ( ! @move_uploaded_file($this->file_temp, $this->upload_path.$this->file_name)) + { + $this->set_error('upload_destination_error'); + return FALSE; + } + } + + /* + * Run the file through the XSS hacking filter + * This helps prevent malicious code from being + * embedded within a file. Scripts can easily + * be disguised as images or other file types. + */ + if ($this->xss_clean == TRUE) + { + $this->do_xss_clean(); + } + + /* + * Set the finalized image dimensions + * This sets the image width/height (assuming the + * file was an image). We use this information + * in the "data" function. + */ + $this->set_image_properties($this->upload_path.$this->file_name); + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Finalized Data Array + * + * Returns an associative array containing all of the information + * related to the upload, allowing the developer easy access in one array. + * + * @access public + * @return array + */ + function data() + { + return array ( + 'file_name' => $this->file_name, + 'file_type' => $this->file_type, + 'file_path' => $this->upload_path, + 'full_path' => $this->upload_path.$this->file_name, + 'raw_name' => str_replace($this->file_ext, '', $this->file_name), + 'orig_name' => $this->orig_name, + 'client_name' => $this->client_name, + 'file_ext' => $this->file_ext, + 'file_size' => $this->file_size, + 'is_image' => $this->is_image(), + 'image_width' => $this->image_width, + 'image_height' => $this->image_height, + 'image_type' => $this->image_type, + 'image_size_str' => $this->image_size_str, + ); + } + + // -------------------------------------------------------------------- + + /** + * Set Upload Path + * + * @access public + * @param string + * @return void + */ + function set_upload_path($path) + { + // Make sure it has a trailing slash + $this->upload_path = rtrim($path, '/').'/'; + } + + // -------------------------------------------------------------------- + + /** + * Set the file name + * + * This function takes a filename/path as input and looks for the + * existence of a file with the same name. If found, it will append a + * number to the end of the filename to avoid overwriting a pre-existing file. + * + * @access public + * @param string + * @param string + * @return string + */ + function set_filename($path, $filename) + { + if ($this->encrypt_name == TRUE) + { + mt_srand(); + $filename = md5(uniqid(mt_rand())).$this->file_ext; + } + + if ( ! file_exists($path.$filename)) + { + return $filename; + } + + $filename = str_replace($this->file_ext, '', $filename); + + $new_filename = ''; + for ($i = 1; $i < 100; $i++) + { + if ( ! file_exists($path.$filename.$i.$this->file_ext)) + { + $new_filename = $filename.$i.$this->file_ext; + break; + } + } + + if ($new_filename == '') + { + $this->set_error('upload_bad_filename'); + return FALSE; + } + else + { + return $new_filename; + } + } + + // -------------------------------------------------------------------- + + /** + * Set Maximum File Size + * + * @access public + * @param integer + * @return void + */ + function set_max_filesize($n) + { + $this->max_size = ((int) $n < 0) ? 0: (int) $n; + } + + // -------------------------------------------------------------------- + + /** + * Set Maximum File Name Length + * + * @access public + * @param integer + * @return void + */ + function set_max_filename($n) + { + $this->max_filename = ((int) $n < 0) ? 0: (int) $n; + } + + // -------------------------------------------------------------------- + + /** + * Set Maximum Image Width + * + * @access public + * @param integer + * @return void + */ + function set_max_width($n) + { + $this->max_width = ((int) $n < 0) ? 0: (int) $n; + } + + // -------------------------------------------------------------------- + + /** + * Set Maximum Image Height + * + * @access public + * @param integer + * @return void + */ + function set_max_height($n) + { + $this->max_height = ((int) $n < 0) ? 0: (int) $n; + } + + // -------------------------------------------------------------------- + + /** + * Set Allowed File Types + * + * @access public + * @param string + * @return void + */ + function set_allowed_types($types) + { + $this->allowed_types = explode('|', $types); + } + + // -------------------------------------------------------------------- + + /** + * Set Image Properties + * + * Uses GD to determine the width/height/type of image + * + * @access public + * @param string + * @return void + */ + function set_image_properties($path = '') + { + if ( ! $this->is_image()) + { + return; + } + + if (function_exists('getimagesize')) + { + if (FALSE !== ($D = @getimagesize($path))) + { + $types = array(1 => 'gif', 2 => 'jpeg', 3 => 'png'); + + $this->image_width = $D['0']; + $this->image_height = $D['1']; + $this->image_type = ( ! isset($types[$D['2']])) ? 'unknown' : $types[$D['2']]; + $this->image_size_str = $D['3']; // string containing height and width + } + } + } + + // -------------------------------------------------------------------- + + /** + * Set XSS Clean + * + * Enables the XSS flag so that the file that was uploaded + * will be run through the XSS filter. + * + * @access public + * @param bool + * @return void + */ + function set_xss_clean($flag = FALSE) + { + $this->xss_clean = ($flag == TRUE) ? TRUE : FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Validate the image + * + * @access public + * @return bool + */ + function is_image() + { + // IE will sometimes return odd mime-types during upload, so here we just standardize all + // jpegs or pngs to the same file type. + + $png_mimes = array('image/x-png'); + $jpeg_mimes = array('image/jpg', 'image/jpe', 'image/jpeg', 'image/pjpeg'); + + if (in_array($this->file_type, $png_mimes)) + { + $this->file_type = 'image/png'; + } + + if (in_array($this->file_type, $jpeg_mimes)) + { + $this->file_type = 'image/jpeg'; + } + + $img_mimes = array( + 'image/gif', + 'image/jpeg', + 'image/png', + ); + + return (in_array($this->file_type, $img_mimes, TRUE)) ? TRUE : FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Verify that the filetype is allowed + * + * @access public + * @return bool + */ + function is_allowed_filetype($ignore_mime = FALSE) + { + if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types)) + { + $this->set_error('upload_no_file_types'); + return FALSE; + } + + $ext = strtolower(ltrim($this->file_ext, '.')); + + if ( ! in_array($ext, $this->allowed_types)) + { + return FALSE; + } + + // Images get some additional checks + $image_types = array('gif', 'jpg', 'jpeg', 'png', 'jpe'); + + if (in_array($ext, $image_types)) + { + if (getimagesize($this->file_temp) === FALSE) + { + return FALSE; + } + } + + if ($ignore_mime === TRUE) + { + return TRUE; + } + + $mime = $this->mimes_types($ext); + + if (is_array($mime)) + { + if (in_array($this->file_type, $mime, TRUE)) + { + return TRUE; + } + } + elseif ($mime == $this->file_type) + { + return TRUE; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Verify that the file is within the allowed size + * + * @access public + * @return bool + */ + function is_allowed_filesize() + { + if ($this->max_size != 0 AND $this->file_size > $this->max_size) + { + return FALSE; + } + else + { + return TRUE; + } + } + + // -------------------------------------------------------------------- + + /** + * Verify that the image is within the allowed width/height + * + * @access public + * @return bool + */ + function is_allowed_dimensions() + { + if ( ! $this->is_image()) + { + return TRUE; + } + + if (function_exists('getimagesize')) + { + $D = @getimagesize($this->file_temp); + + if ($this->max_width > 0 AND $D['0'] > $this->max_width) + { + return FALSE; + } + + if ($this->max_height > 0 AND $D['1'] > $this->max_height) + { + return FALSE; + } + + return TRUE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Validate Upload Path + * + * Verifies that it is a valid upload path with proper permissions. + * + * + * @access public + * @return bool + */ + function validate_upload_path() + { + if ($this->upload_path == '') + { + $this->set_error('upload_no_filepath'); + return FALSE; + } + + if (function_exists('realpath') AND @realpath($this->upload_path) !== FALSE) + { + $this->upload_path = str_replace("\\", "/", realpath($this->upload_path)); + } + + if ( ! @is_dir($this->upload_path)) + { + $this->set_error('upload_no_filepath'); + return FALSE; + } + + if ( ! is_really_writable($this->upload_path)) + { + $this->set_error('upload_not_writable'); + return FALSE; + } + + $this->upload_path = preg_replace("/(.+?)\/*$/", "\\1/", $this->upload_path); + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Extract the file extension + * + * @access public + * @param string + * @return string + */ + function get_extension($filename) + { + $x = explode('.', $filename); + return '.'.end($x); + } + + // -------------------------------------------------------------------- + + /** + * Clean the file name for security + * + * @access public + * @param string + * @return string + */ + function clean_file_name($filename) + { + $bad = array( + "", + "'", + "<", + ">", + '"', + '&', + '$', + '=', + ';', + '?', + '/', + "%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 + * + * @access public + * @param string + * @return string + */ + 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. + * + * @access public + * @return void + */ + function do_xss_clean() + { + $file = $this->upload_path.$this->file_name; + + if (filesize($file) == 0) + { + return FALSE; + } + + if (($data = @file_get_contents($file)) === FALSE) + { + return FALSE; + } + + if ( ! $fp = @fopen($file, FOPEN_READ_WRITE)) + { + return FALSE; + } + + $CI =& get_instance(); + $data = $CI->input->xss_clean($data); + + flock($fp, LOCK_EX); + fwrite($fp, $data); + flock($fp, LOCK_UN); + fclose($fp); + } + + // -------------------------------------------------------------------- + + /** + * Set an error message + * + * @access public + * @param string + * @return void + */ + function set_error($msg) + { + $CI =& get_instance(); + + if (is_array($msg)) + { + foreach ($msg as $val) + { + $msg = (T_($val) == FALSE) ? $val : T_($val); + $this->error_msg[] = $msg; + log_message('error', $msg); + } + } + else + { + $msg = (T_($msg) == FALSE) ? $msg : T_($msg); + $this->error_msg[] = $msg; + log_message('error', $msg); + } + } + + // -------------------------------------------------------------------- + + /** + * Display the error message + * + * @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; + } + + // -------------------------------------------------------------------- + + /** + * List of Mime Types + * + * This is a list of mime types. We use it to validate + * the "allowed types" set by the developer + * + * @access public + * @param string + * @return string + */ + function mimes_types($mime) + { + global $mimes; + + if (count($this->mimes) == 0) + { + if (@require_once(APPPATH.'config/mimes'.EXT)) + { + $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 + * + * @access private + * @param string + * @return string + */ + function _prep_filename($filename) + { + if (strpos($filename, '.') === FALSE) + { + 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; + } + + // -------------------------------------------------------------------- + +} +// END Upload Class + +/* End of file Upload.php */ /* Location: ./system/libraries/Upload.php */ \ No newline at end of file diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php index 00cbf69..65e686c 100644 --- a/system/libraries/User_agent.php +++ b/system/libraries/User_agent.php @@ -1,502 +1,502 @@ -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 - */ - function _load_agent_file() - { - if ( ! @include(APPPATH.'config/user_agents'.EXT)) - { - 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 - */ - function _compile_data() - { - $this->_set_platform(); - - foreach (array('_set_browser', '_set_robot', '_set_mobile') as $function) - { - if ($this->$function() === TRUE) - { - break; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Set the Platform - * - * @access private - * @return mixed - */ - 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 - */ - 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 - */ - 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 - */ - 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 - */ - 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 - */ - 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 - */ - function is_browser() - { - return $this->is_browser; - } - - // -------------------------------------------------------------------- - - /** - * Is Robot - * - * @access public - * @return bool - */ - function is_robot() - { - return $this->is_robot; - } - - // -------------------------------------------------------------------- - - /** - * Is Mobile - * - * @access public - * @return bool - */ - function is_mobile() - { - return $this->is_mobile; - } - - // -------------------------------------------------------------------- - - /** - * Is this a referral from another site? - * - * @access public - * @return bool - */ - function is_referral() - { - return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Agent String - * - * @access public - * @return string - */ - function agent_string() - { - return $this->agent; - } - - // -------------------------------------------------------------------- - - /** - * Get Platform - * - * @access public - * @return string - */ - function platform() - { - return $this->platform; - } - - // -------------------------------------------------------------------- - - /** - * Get Browser Name - * - * @access public - * @return string - */ - function browser() - { - return $this->browser; - } - - // -------------------------------------------------------------------- - - /** - * Get the Browser Version - * - * @access public - * @return string - */ - function version() - { - return $this->version; - } - - // -------------------------------------------------------------------- - - /** - * Get The Robot Name - * - * @access public - * @return string - */ - function robot() - { - return $this->robot; - } - // -------------------------------------------------------------------- - - /** - * Get the Mobile Device - * - * @access public - * @return string - */ - function mobile() - { - return $this->mobile; - } - - // -------------------------------------------------------------------- - - /** - * Get the referrer - * - * @access public - * @return bool - */ - function referrer() - { - return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? '' : trim($_SERVER['HTTP_REFERER']); - } - - // -------------------------------------------------------------------- - - /** - * Get the accepted languages - * - * @access public - * @return array - */ - function languages() - { - if (count($this->languages) == 0) - { - $this->_set_languages(); - } - - return $this->languages; - } - - // -------------------------------------------------------------------- - - /** - * Get the accepted Character Sets - * - * @access public - * @return array - */ - function charsets() - { - if (count($this->charsets) == 0) - { - $this->_set_charsets(); - } - - return $this->charsets; - } - - // -------------------------------------------------------------------- - - /** - * Test for a particular language - * - * @access public - * @return bool - */ - function accept_lang($lang = 'en') - { - return (in_array(strtolower($lang), $this->languages(), TRUE)) ? TRUE : FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Test for a particular character set - * - * @access public - * @return bool - */ - function accept_charset($charset = 'utf-8') - { - return (in_array(strtolower($charset), $this->charsets(), TRUE)) ? TRUE : FALSE; - } - - -} - - -/* End of file User_agent.php */ +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 + */ + function _load_agent_file() + { + if ( ! @include(APPPATH.'config/user_agents'.EXT)) + { + 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 + */ + function _compile_data() + { + $this->_set_platform(); + + foreach (array('_set_browser', '_set_robot', '_set_mobile') as $function) + { + if ($this->$function() === TRUE) + { + break; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Set the Platform + * + * @access private + * @return mixed + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + function is_browser() + { + return $this->is_browser; + } + + // -------------------------------------------------------------------- + + /** + * Is Robot + * + * @access public + * @return bool + */ + function is_robot() + { + return $this->is_robot; + } + + // -------------------------------------------------------------------- + + /** + * Is Mobile + * + * @access public + * @return bool + */ + function is_mobile() + { + return $this->is_mobile; + } + + // -------------------------------------------------------------------- + + /** + * Is this a referral from another site? + * + * @access public + * @return bool + */ + function is_referral() + { + return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Agent String + * + * @access public + * @return string + */ + function agent_string() + { + return $this->agent; + } + + // -------------------------------------------------------------------- + + /** + * Get Platform + * + * @access public + * @return string + */ + function platform() + { + return $this->platform; + } + + // -------------------------------------------------------------------- + + /** + * Get Browser Name + * + * @access public + * @return string + */ + function browser() + { + return $this->browser; + } + + // -------------------------------------------------------------------- + + /** + * Get the Browser Version + * + * @access public + * @return string + */ + function version() + { + return $this->version; + } + + // -------------------------------------------------------------------- + + /** + * Get The Robot Name + * + * @access public + * @return string + */ + function robot() + { + return $this->robot; + } + // -------------------------------------------------------------------- + + /** + * Get the Mobile Device + * + * @access public + * @return string + */ + function mobile() + { + return $this->mobile; + } + + // -------------------------------------------------------------------- + + /** + * Get the referrer + * + * @access public + * @return bool + */ + function referrer() + { + return ( ! isset($_SERVER['HTTP_REFERER']) OR $_SERVER['HTTP_REFERER'] == '') ? '' : trim($_SERVER['HTTP_REFERER']); + } + + // -------------------------------------------------------------------- + + /** + * Get the accepted languages + * + * @access public + * @return array + */ + function languages() + { + if (count($this->languages) == 0) + { + $this->_set_languages(); + } + + return $this->languages; + } + + // -------------------------------------------------------------------- + + /** + * Get the accepted Character Sets + * + * @access public + * @return array + */ + function charsets() + { + if (count($this->charsets) == 0) + { + $this->_set_charsets(); + } + + return $this->charsets; + } + + // -------------------------------------------------------------------- + + /** + * Test for a particular language + * + * @access public + * @return bool + */ + function accept_lang($lang = 'en') + { + return (in_array(strtolower($lang), $this->languages(), TRUE)) ? TRUE : FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Test for a particular character set + * + * @access public + * @return bool + */ + function accept_charset($charset = 'utf-8') + { + return (in_array(strtolower($charset), $this->charsets(), TRUE)) ? TRUE : FALSE; + } + + +} + + +/* End of file User_agent.php */ /* Location: ./system/libraries/User_agent.php */ \ No newline at end of file diff --git a/system/libraries/Validation.php b/system/libraries/Validation.php index 22ed9e3..95f07b1 100644 --- a/system/libraries/Validation.php +++ b/system/libraries/Validation.php @@ -1,875 +1,872 @@ -'; - var $_error_suffix = '

    '; - - - - /** - * Constructor - * - */ - function CI_Validation() - { - $this->CI =& get_instance(); - - if (function_exists('mb_internal_encoding')) - { - mb_internal_encoding($this->CI->config->item('charset')); - } - - log_message('debug', "Validation Class Initialized"); - } - - // -------------------------------------------------------------------- - - /** - * Set Fields - * - * This function takes an array of field names as input - * and generates class variables with the same name, which will - * either be blank or contain the $_POST value corresponding to it - * - * @access public - * @param string - * @param string - * @return void - */ - function set_fields($data = '', $field = '') - { - if ($data == '') - { - if (count($this->_fields) == 0) - { - return FALSE; - } - } - else - { - if ( ! is_array($data)) - { - $data = array($data => $field); - } - - if (count($data) > 0) - { - $this->_fields = $data; - } - } - - foreach($this->_fields as $key => $val) - { - $this->$key = ( ! isset($_POST[$key])) ? '' : $this->prep_for_form($_POST[$key]); - - $error = $key.'_error'; - if ( ! isset($this->$error)) - { - $this->$error = ''; - } - } - } - - // -------------------------------------------------------------------- - - /** - * Set Rules - * - * This function takes an array of field names and validation - * rules as input ad simply stores is for use later. - * - * @access public - * @param mixed - * @param string - * @return void - */ - function set_rules($data, $rules = '') - { - if ( ! is_array($data)) - { - if ($rules == '') - return; - - $data = array($data => $rules); - } - - foreach ($data as $key => $val) - { - $this->_rules[$key] = $val; - } - } - - // -------------------------------------------------------------------- - - /** - * Set Error Message - * - * Lets users set their own error messages on the fly. Note: The key - * name has to match the function name that it corresponds to. - * - * @access public - * @param string - * @param string - * @return string - */ - function set_message($lang, $val = '') - { - if ( ! is_array($lang)) - { - $lang = array($lang => $val); - } - - $this->_error_messages = array_merge($this->_error_messages, $lang); - } - - // -------------------------------------------------------------------- - - /** - * Set The Error Delimiter - * - * Permits a prefix/suffix to be added to each error message - * - * @access public - * @param string - * @param string - * @return void - */ - function set_error_delimiters($prefix = '

    ', $suffix = '

    ') - { - $this->_error_prefix = $prefix; - $this->_error_suffix = $suffix; - } - - // -------------------------------------------------------------------- - - /** - * Run the Validator - * - * This function does all the work. - * - * @access public - * @return bool - */ - function run() - { - // Do we even have any data to process? Mm? - if (count($_POST) == 0 OR count($this->_rules) == 0) - { - return FALSE; - } - - // Load the language file containing error messages - $this->CI->lang->load('validation'); - - // Cycle through the rules and test for errors - foreach ($this->_rules as $field => $rules) - { - //Explode out the rules! - $ex = explode('|', $rules); - - // Is the field required? If not, if the field is blank we'll move on to the next test - if ( ! in_array('required', $ex, TRUE)) - { - if ( ! isset($_POST[$field]) OR $_POST[$field] == '') - { - continue; - } - } - - /* - * Are we dealing with an "isset" rule? - * - * Before going further, we'll see if one of the rules - * is to check whether the item is set (typically this - * applies only to checkboxes). If so, we'll - * test for it here since there's not reason to go - * further - */ - if ( ! isset($_POST[$field])) - { - if (in_array('isset', $ex, TRUE) OR in_array('required', $ex)) - { - if ( ! isset($this->_error_messages['isset'])) - { - if (FALSE === ($line = $this->CI->lang->line('isset'))) - { - $line = 'The field was not set'; - } - } - else - { - $line = $this->_error_messages['isset']; - } - - // Build the error message - $mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field]; - $message = sprintf($line, $mfield); - - // Set the error variable. Example: $this->username_error - $error = $field.'_error'; - $this->$error = $this->_error_prefix.$message.$this->_error_suffix; - $this->_error_array[] = $message; - } - - continue; - } - - /* - * Set the current field - * - * The various prepping functions need to know the - * current field name so they can do this: - * - * $_POST[$this->_current_field] == 'bla bla'; - */ - $this->_current_field = $field; - - // Cycle through the rules! - foreach ($ex As $rule) - { - // Is the rule a callback? - $callback = FALSE; - if (substr($rule, 0, 9) == 'callback_') - { - $rule = substr($rule, 9); - $callback = TRUE; - } - - // Strip the parameter (if exists) from the rule - // Rules can contain a parameter: max_length[5] - $param = FALSE; - if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match)) - { - $rule = $match[1]; - $param = $match[2]; - } - - // Call the function that corresponds to the rule - if ($callback === TRUE) - { - if ( ! method_exists($this->CI, $rule)) - { - continue; - } - - $result = $this->CI->$rule($_POST[$field], $param); - - // If the field isn't required and we just processed a callback we'll move on... - if ( ! in_array('required', $ex, TRUE) AND $result !== FALSE) - { - continue 2; - } - - } - else - { - if ( ! method_exists($this, $rule)) - { - /* - * Run the native PHP function if called for - * - * If our own wrapper function doesn't exist we see - * if a native PHP function does. Users can use - * any native PHP function call that has one param. - */ - if (function_exists($rule)) - { - $_POST[$field] = $rule($_POST[$field]); - $this->$field = $_POST[$field]; - } - - continue; - } - - $result = $this->$rule($_POST[$field], $param); - } - - // Did the rule test negatively? If so, grab the error. - if ($result === FALSE) - { - if ( ! isset($this->_error_messages[$rule])) - { - if (FALSE === ($line = $this->CI->lang->line($rule))) - { - $line = 'Unable to access an error message corresponding to your field name.'; - } - } - else - { - $line = $this->_error_messages[$rule]; - } - - // Build the error message - $mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field]; - $mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param]; - $message = sprintf($line, $mfield, $mparam); - - // Set the error variable. Example: $this->username_error - $error = $field.'_error'; - $this->$error = $this->_error_prefix.$message.$this->_error_suffix; - - // Add the error to the error array - $this->_error_array[] = $message; - continue 2; - } - } - - } - - $total_errors = count($this->_error_array); - - /* - * Recompile the class variables - * - * If any prepping functions were called the $_POST data - * might now be different then the corresponding class - * variables so we'll set them anew. - */ - if ($total_errors > 0) - { - $this->_safe_form_data = TRUE; - } - - $this->set_fields(); - - // Did we end up with any errors? - if ($total_errors == 0) - { - return TRUE; - } - - // Generate the error string - foreach ($this->_error_array as $val) - { - $this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n"; - } - - return FALSE; - } - - // -------------------------------------------------------------------- - - /** - * Required - * - * @access public - * @param string - * @return bool - */ - function required($str) - { - if ( ! is_array($str)) - { - return (trim($str) == '') ? FALSE : TRUE; - } - else - { - return ( ! empty($str)); - } - } - - // -------------------------------------------------------------------- - - /** - * Match one field to another - * - * @access public - * @param string - * @param field - * @return bool - */ - function matches($str, $field) - { - if ( ! isset($_POST[$field])) - { - return FALSE; - } - - return ($str !== $_POST[$field]) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Minimum Length - * - * @access public - * @param string - * @param value - * @return bool - */ - function min_length($str, $val) - { - if (preg_match("/[^0-9]/", $val)) - { - return FALSE; - } - - if (function_exists('mb_strlen')) - { - return (mb_strlen($str) < $val) ? FALSE : TRUE; - } - - return (strlen($str) < $val) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Max Length - * - * @access public - * @param string - * @param value - * @return bool - */ - function max_length($str, $val) - { - if (preg_match("/[^0-9]/", $val)) - { - return FALSE; - } - - if (function_exists('mb_strlen')) - { - return (mb_strlen($str) > $val) ? FALSE : TRUE; - } - - return (strlen($str) > $val) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Exact Length - * - * @access public - * @param string - * @param value - * @return bool - */ - function exact_length($str, $val) - { - if (preg_match("/[^0-9]/", $val)) - { - return FALSE; - } - - if (function_exists('mb_strlen')) - { - return (mb_strlen($str) != $val) ? FALSE : TRUE; - } - - return (strlen($str) != $val) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Valid Email - * - * @access public - * @param string - * @return bool - */ - function valid_email($str) - { - return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Valid Emails - * - * @access public - * @param string - * @return bool - */ - function valid_emails($str) - { - if (strpos($str, ',') === FALSE) - { - return $this->valid_email(trim($str)); - } - - foreach(explode(',', $str) as $email) - { - if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE) - { - return FALSE; - } - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Validate IP Address - * - * @access public - * @param string - * @return string - */ - function valid_ip($ip) - { - return $this->CI->input->valid_ip($ip); - } - - // -------------------------------------------------------------------- - - /** - * Alpha - * - * @access public - * @param string - * @return bool - */ - function alpha($str) - { - return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Alpha-numeric - * - * @access public - * @param string - * @return bool - */ - function alpha_numeric($str) - { - return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Alpha-numeric with underscores and dashes - * - * @access public - * @param string - * @return bool - */ - function alpha_dash($str) - { - return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Numeric - * - * @access public - * @param string - * @return bool - */ - function numeric($str) - { - return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str); - - } - - // -------------------------------------------------------------------- - - /** - * Is Numeric - * - * @access public - * @param string - * @return bool - */ - function is_numeric($str) - { - return ( ! is_numeric($str)) ? FALSE : TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Integer - * - * @access public - * @param string - * @return bool - */ - function integer($str) - { - return (bool)preg_match( '/^[\-+]?[0-9]+$/', $str); - } - - // -------------------------------------------------------------------- - - /** - * Is a Natural number (0,1,2,3, etc.) - * - * @access public - * @param string - * @return bool - */ - function is_natural($str) - { - return (bool)preg_match( '/^[0-9]+$/', $str); - } - - // -------------------------------------------------------------------- - - /** - * Is a Natural number, but not a zero (1,2,3, etc.) - * - * @access public - * @param string - * @return bool - */ - function is_natural_no_zero($str) - { - if ( ! preg_match( '/^[0-9]+$/', $str)) - { - return FALSE; - } - - if ($str == 0) - { - return FALSE; - } - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Valid Base64 - * - * Tests a string for characters outside of the Base64 alphabet - * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045 - * - * @access public - * @param string - * @return bool - */ - function valid_base64($str) - { - return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); - } - - // -------------------------------------------------------------------- - - /** - * Set Select - * - * Enables pull-down lists to be set to the value the user - * selected in the event of an error - * - * @access public - * @param string - * @param string - * @return string - */ - function set_select($field = '', $value = '') - { - if ($field == '' OR $value == '' OR ! isset($_POST[$field])) - { - return ''; - } - - if ($_POST[$field] == $value) - { - return ' selected="selected"'; - } - } - - // -------------------------------------------------------------------- - - /** - * Set Radio - * - * Enables radio buttons to be set to the value the user - * selected in the event of an error - * - * @access public - * @param string - * @param string - * @return string - */ - function set_radio($field = '', $value = '') - { - if ($field == '' OR $value == '' OR ! isset($_POST[$field])) - { - return ''; - } - - if ($_POST[$field] == $value) - { - return ' checked="checked"'; - } - } - - // -------------------------------------------------------------------- - - /** - * Set Checkbox - * - * Enables checkboxes to be set to the value the user - * selected in the event of an error - * - * @access public - * @param string - * @param string - * @return string - */ - function set_checkbox($field = '', $value = '') - { - if ($field == '' OR $value == '' OR ! isset($_POST[$field])) - { - return ''; - } - - if ($_POST[$field] == $value) - { - return ' checked="checked"'; - } - } - - // -------------------------------------------------------------------- - - /** - * Prep data for form - * - * This function allows HTML to be safely shown in a form. - * Special characters are converted. - * - * @access public - * @param string - * @return string - */ - function prep_for_form($data = '') - { - if (is_array($data)) - { - foreach ($data as $key => $val) - { - $data[$key] = $this->prep_for_form($val); - } - - return $data; - } - - if ($this->_safe_form_data == FALSE OR $data == '') - { - return $data; - } - - return str_replace(array("'", '"', '<', '>'), array("'", """, '<', '>'), stripslashes($data)); - } - - // -------------------------------------------------------------------- - - /** - * Prep URL - * - * @access public - * @param string - * @return string - */ - function prep_url($str = '') - { - if ($str == 'http://' OR $str == '') - { - $_POST[$this->_current_field] = ''; - return; - } - - if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://') - { - $str = 'http://'.$str; - } - - $_POST[$this->_current_field] = $str; - } - - // -------------------------------------------------------------------- - - /** - * Strip Image Tags - * - * @access public - * @param string - * @return string - */ - function strip_image_tags($str) - { - $_POST[$this->_current_field] = $this->CI->input->strip_image_tags($str); - } - - // -------------------------------------------------------------------- - - /** - * XSS Clean - * - * @access public - * @param string - * @return string - */ - function xss_clean($str) - { - $_POST[$this->_current_field] = $this->CI->input->xss_clean($str); - } - - // -------------------------------------------------------------------- - - /** - * Convert PHP tags to entities - * - * @access public - * @param string - * @return string - */ - function encode_php_tags($str) - { - $_POST[$this->_current_field] = str_replace(array(''), array('<?php', '<?PHP', '<?', '?>'), $str); - } - -} -// END Validation Class - -/* End of file Validation.php */ +'; + var $_error_suffix = '

    '; + + + + /** + * Constructor + * + */ + function CI_Validation() + { + $this->CI =& get_instance(); + + if (function_exists('mb_internal_encoding')) + { + mb_internal_encoding($this->CI->config->item('charset')); + } + + log_message('debug', "Validation Class Initialized"); + } + + // -------------------------------------------------------------------- + + /** + * Set Fields + * + * This function takes an array of field names as input + * and generates class variables with the same name, which will + * either be blank or contain the $_POST value corresponding to it + * + * @access public + * @param string + * @param string + * @return void + */ + function set_fields($data = '', $field = '') + { + if ($data == '') + { + if (count($this->_fields) == 0) + { + return FALSE; + } + } + else + { + if ( ! is_array($data)) + { + $data = array($data => $field); + } + + if (count($data) > 0) + { + $this->_fields = $data; + } + } + + foreach($this->_fields as $key => $val) + { + $this->$key = ( ! isset($_POST[$key])) ? '' : $this->prep_for_form($_POST[$key]); + + $error = $key.'_error'; + if ( ! isset($this->$error)) + { + $this->$error = ''; + } + } + } + + // -------------------------------------------------------------------- + + /** + * Set Rules + * + * This function takes an array of field names and validation + * rules as input ad simply stores is for use later. + * + * @access public + * @param mixed + * @param string + * @return void + */ + function set_rules($data, $rules = '') + { + if ( ! is_array($data)) + { + if ($rules == '') + return; + + $data = array($data => $rules); + } + + foreach ($data as $key => $val) + { + $this->_rules[$key] = $val; + } + } + + // -------------------------------------------------------------------- + + /** + * Set Error Message + * + * Lets users set their own error messages on the fly. Note: The key + * name has to match the function name that it corresponds to. + * + * @access public + * @param string + * @param string + * @return string + */ + function set_message($lang, $val = '') + { + if ( ! is_array($lang)) + { + $lang = array($lang => $val); + } + + $this->_error_messages = array_merge($this->_error_messages, $lang); + } + + // -------------------------------------------------------------------- + + /** + * Set The Error Delimiter + * + * Permits a prefix/suffix to be added to each error message + * + * @access public + * @param string + * @param string + * @return void + */ + function set_error_delimiters($prefix = '

    ', $suffix = '

    ') + { + $this->_error_prefix = $prefix; + $this->_error_suffix = $suffix; + } + + // -------------------------------------------------------------------- + + /** + * Run the Validator + * + * This function does all the work. + * + * @access public + * @return bool + */ + function run() + { + // Do we even have any data to process? Mm? + if (count($_POST) == 0 OR count($this->_rules) == 0) + { + return FALSE; + } + + // Cycle through the rules and test for errors + foreach ($this->_rules as $field => $rules) + { + //Explode out the rules! + $ex = explode('|', $rules); + + // Is the field required? If not, if the field is blank we'll move on to the next test + if ( ! in_array('required', $ex, TRUE)) + { + if ( ! isset($_POST[$field]) OR $_POST[$field] == '') + { + continue; + } + } + + /* + * Are we dealing with an "isset" rule? + * + * Before going further, we'll see if one of the rules + * is to check whether the item is set (typically this + * applies only to checkboxes). If so, we'll + * test for it here since there's not reason to go + * further + */ + if ( ! isset($_POST[$field])) + { + if (in_array('isset', $ex, TRUE) OR in_array('required', $ex)) + { + if ( ! isset($this->_error_messages['isset'])) + { + if (FALSE === ($line = T_('isset'))) + { + $line = 'The field was not set'; + } + } + else + { + $line = $this->_error_messages['isset']; + } + + // Build the error message + $mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field]; + $message = sprintf($line, $mfield); + + // Set the error variable. Example: $this->username_error + $error = $field.'_error'; + $this->$error = $this->_error_prefix.$message.$this->_error_suffix; + $this->_error_array[] = $message; + } + + continue; + } + + /* + * Set the current field + * + * The various prepping functions need to know the + * current field name so they can do this: + * + * $_POST[$this->_current_field] == 'bla bla'; + */ + $this->_current_field = $field; + + // Cycle through the rules! + foreach ($ex As $rule) + { + // Is the rule a callback? + $callback = FALSE; + if (substr($rule, 0, 9) == 'callback_') + { + $rule = substr($rule, 9); + $callback = TRUE; + } + + // Strip the parameter (if exists) from the rule + // Rules can contain a parameter: max_length[5] + $param = FALSE; + if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match)) + { + $rule = $match[1]; + $param = $match[2]; + } + + // Call the function that corresponds to the rule + if ($callback === TRUE) + { + if ( ! method_exists($this->CI, $rule)) + { + continue; + } + + $result = $this->CI->$rule($_POST[$field], $param); + + // If the field isn't required and we just processed a callback we'll move on... + if ( ! in_array('required', $ex, TRUE) AND $result !== FALSE) + { + continue 2; + } + + } + else + { + if ( ! method_exists($this, $rule)) + { + /* + * Run the native PHP function if called for + * + * If our own wrapper function doesn't exist we see + * if a native PHP function does. Users can use + * any native PHP function call that has one param. + */ + if (function_exists($rule)) + { + $_POST[$field] = $rule($_POST[$field]); + $this->$field = $_POST[$field]; + } + + continue; + } + + $result = $this->$rule($_POST[$field], $param); + } + + // Did the rule test negatively? If so, grab the error. + if ($result === FALSE) + { + if ( ! isset($this->_error_messages[$rule])) + { + if (FALSE === ($line = T_($rule))) + { + $line = 'Unable to access an error message corresponding to your field name.'; + } + } + else + { + $line = $this->_error_messages[$rule]; + } + + // Build the error message + $mfield = ( ! isset($this->_fields[$field])) ? $field : $this->_fields[$field]; + $mparam = ( ! isset($this->_fields[$param])) ? $param : $this->_fields[$param]; + $message = sprintf($line, $mfield, $mparam); + + // Set the error variable. Example: $this->username_error + $error = $field.'_error'; + $this->$error = $this->_error_prefix.$message.$this->_error_suffix; + + // Add the error to the error array + $this->_error_array[] = $message; + continue 2; + } + } + + } + + $total_errors = count($this->_error_array); + + /* + * Recompile the class variables + * + * If any prepping functions were called the $_POST data + * might now be different then the corresponding class + * variables so we'll set them anew. + */ + if ($total_errors > 0) + { + $this->_safe_form_data = TRUE; + } + + $this->set_fields(); + + // Did we end up with any errors? + if ($total_errors == 0) + { + return TRUE; + } + + // Generate the error string + foreach ($this->_error_array as $val) + { + $this->error_string .= $this->_error_prefix.$val.$this->_error_suffix."\n"; + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** + * Required + * + * @access public + * @param string + * @return bool + */ + function required($str) + { + if ( ! is_array($str)) + { + return (trim($str) == '') ? FALSE : TRUE; + } + else + { + return ( ! empty($str)); + } + } + + // -------------------------------------------------------------------- + + /** + * Match one field to another + * + * @access public + * @param string + * @param field + * @return bool + */ + function matches($str, $field) + { + if ( ! isset($_POST[$field])) + { + return FALSE; + } + + return ($str !== $_POST[$field]) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Minimum Length + * + * @access public + * @param string + * @param value + * @return bool + */ + function min_length($str, $val) + { + if (preg_match("/[^0-9]/", $val)) + { + return FALSE; + } + + if (function_exists('mb_strlen')) + { + return (mb_strlen($str) < $val) ? FALSE : TRUE; + } + + return (strlen($str) < $val) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Max Length + * + * @access public + * @param string + * @param value + * @return bool + */ + function max_length($str, $val) + { + if (preg_match("/[^0-9]/", $val)) + { + return FALSE; + } + + if (function_exists('mb_strlen')) + { + return (mb_strlen($str) > $val) ? FALSE : TRUE; + } + + return (strlen($str) > $val) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Exact Length + * + * @access public + * @param string + * @param value + * @return bool + */ + function exact_length($str, $val) + { + if (preg_match("/[^0-9]/", $val)) + { + return FALSE; + } + + if (function_exists('mb_strlen')) + { + return (mb_strlen($str) != $val) ? FALSE : TRUE; + } + + return (strlen($str) != $val) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Valid Email + * + * @access public + * @param string + * @return bool + */ + function valid_email($str) + { + return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Valid Emails + * + * @access public + * @param string + * @return bool + */ + function valid_emails($str) + { + if (strpos($str, ',') === FALSE) + { + return $this->valid_email(trim($str)); + } + + foreach(explode(',', $str) as $email) + { + if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE) + { + return FALSE; + } + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Validate IP Address + * + * @access public + * @param string + * @return string + */ + function valid_ip($ip) + { + return $this->CI->input->valid_ip($ip); + } + + // -------------------------------------------------------------------- + + /** + * Alpha + * + * @access public + * @param string + * @return bool + */ + function alpha($str) + { + return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Alpha-numeric + * + * @access public + * @param string + * @return bool + */ + function alpha_numeric($str) + { + return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Alpha-numeric with underscores and dashes + * + * @access public + * @param string + * @return bool + */ + function alpha_dash($str) + { + return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Numeric + * + * @access public + * @param string + * @return bool + */ + function numeric($str) + { + return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str); + + } + + // -------------------------------------------------------------------- + + /** + * Is Numeric + * + * @access public + * @param string + * @return bool + */ + function is_numeric($str) + { + return ( ! is_numeric($str)) ? FALSE : TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Integer + * + * @access public + * @param string + * @return bool + */ + function integer($str) + { + return (bool)preg_match( '/^[\-+]?[0-9]+$/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Is a Natural number (0,1,2,3, etc.) + * + * @access public + * @param string + * @return bool + */ + function is_natural($str) + { + return (bool)preg_match( '/^[0-9]+$/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Is a Natural number, but not a zero (1,2,3, etc.) + * + * @access public + * @param string + * @return bool + */ + function is_natural_no_zero($str) + { + if ( ! preg_match( '/^[0-9]+$/', $str)) + { + return FALSE; + } + + if ($str == 0) + { + return FALSE; + } + + return TRUE; + } + + // -------------------------------------------------------------------- + + /** + * Valid Base64 + * + * Tests a string for characters outside of the Base64 alphabet + * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045 + * + * @access public + * @param string + * @return bool + */ + function valid_base64($str) + { + return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str); + } + + // -------------------------------------------------------------------- + + /** + * Set Select + * + * Enables pull-down lists to be set to the value the user + * selected in the event of an error + * + * @access public + * @param string + * @param string + * @return string + */ + function set_select($field = '', $value = '') + { + if ($field == '' OR $value == '' OR ! isset($_POST[$field])) + { + return ''; + } + + if ($_POST[$field] == $value) + { + return ' selected="selected"'; + } + } + + // -------------------------------------------------------------------- + + /** + * Set Radio + * + * Enables radio buttons to be set to the value the user + * selected in the event of an error + * + * @access public + * @param string + * @param string + * @return string + */ + function set_radio($field = '', $value = '') + { + if ($field == '' OR $value == '' OR ! isset($_POST[$field])) + { + return ''; + } + + if ($_POST[$field] == $value) + { + return ' checked="checked"'; + } + } + + // -------------------------------------------------------------------- + + /** + * Set Checkbox + * + * Enables checkboxes to be set to the value the user + * selected in the event of an error + * + * @access public + * @param string + * @param string + * @return string + */ + function set_checkbox($field = '', $value = '') + { + if ($field == '' OR $value == '' OR ! isset($_POST[$field])) + { + return ''; + } + + if ($_POST[$field] == $value) + { + return ' checked="checked"'; + } + } + + // -------------------------------------------------------------------- + + /** + * Prep data for form + * + * This function allows HTML to be safely shown in a form. + * Special characters are converted. + * + * @access public + * @param string + * @return string + */ + function prep_for_form($data = '') + { + if (is_array($data)) + { + foreach ($data as $key => $val) + { + $data[$key] = $this->prep_for_form($val); + } + + return $data; + } + + if ($this->_safe_form_data == FALSE OR $data == '') + { + return $data; + } + + return str_replace(array("'", '"', '<', '>'), array("'", """, '<', '>'), stripslashes($data)); + } + + // -------------------------------------------------------------------- + + /** + * Prep URL + * + * @access public + * @param string + * @return string + */ + function prep_url($str = '') + { + if ($str == 'http://' OR $str == '') + { + $_POST[$this->_current_field] = ''; + return; + } + + if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://') + { + $str = 'http://'.$str; + } + + $_POST[$this->_current_field] = $str; + } + + // -------------------------------------------------------------------- + + /** + * Strip Image Tags + * + * @access public + * @param string + * @return string + */ + function strip_image_tags($str) + { + $_POST[$this->_current_field] = $this->CI->input->strip_image_tags($str); + } + + // -------------------------------------------------------------------- + + /** + * XSS Clean + * + * @access public + * @param string + * @return string + */ + function xss_clean($str) + { + $_POST[$this->_current_field] = $this->CI->input->xss_clean($str); + } + + // -------------------------------------------------------------------- + + /** + * Convert PHP tags to entities + * + * @access public + * @param string + * @return string + */ + function encode_php_tags($str) + { + $_POST[$this->_current_field] = str_replace(array(''), array('<?php', '<?PHP', '<?', '?>'), $str); + } + +} +// END Validation Class + +/* End of file Validation.php */ /* Location: ./system/libraries/Validation.php */ \ No newline at end of file diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 10e338b..c48381b 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1,1421 +1,1421 @@ -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 receieved 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) && isset($value['0'])) - { - 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; - - function XML_RPC_Client($path, $server, $port=80) - { - parent::CI_Xmlrpc(); - - $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(); - - function XML_RPC_Response($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] = $CI->input->xss_clean($array[$key]); - } - } - - $result = $array; - } - else - { - $result = $this->xmlrpc_decoder($this->val); - - if (is_array($result)) - { - $result = $this->decode($result); - } - else - { - $result = $CI->input->xss_clean($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)) - { - if ($utc == 1) - $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); - else - $t = mktime($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(); - - function XML_RPC_Message($method, $pars=0) - { - parent::CI_Xmlrpc(); - - $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 - { - $array[$key] = $CI->input->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[] = $CI->input->xss_clean($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; - - function XML_RPC_Values($val=-1, $type='') - { - parent::CI_Xmlrpc(); - - 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:%M:%S", $time); - } - else - { - if (function_exists('gmstrftime')) - $t = gmstrftime("%Y%m%dT%H:%M:%S", $time); - else - $t = strftime("%Y%m%dT%H:%M:%S", $time - date('Z')); - } - return $t; - } - -} -// END XML_RPC_Values Class - -/* End of file Xmlrpc.php */ +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 receieved 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) && isset($value['0'])) + { + 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; + + function XML_RPC_Client($path, $server, $port=80) + { + parent::CI_Xmlrpc(); + + $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(); + + function XML_RPC_Response($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] = $CI->input->xss_clean($array[$key]); + } + } + + $result = $array; + } + else + { + $result = $this->xmlrpc_decoder($this->val); + + if (is_array($result)) + { + $result = $this->decode($result); + } + else + { + $result = $CI->input->xss_clean($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)) + { + if ($utc == 1) + $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); + else + $t = mktime($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(); + + function XML_RPC_Message($method, $pars=0) + { + parent::CI_Xmlrpc(); + + $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 + { + $array[$key] = $CI->input->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[] = $CI->input->xss_clean($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; + + function XML_RPC_Values($val=-1, $type='') + { + parent::CI_Xmlrpc(); + + 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:%M:%S", $time); + } + else + { + if (function_exists('gmstrftime')) + $t = gmstrftime("%Y%m%dT%H:%M:%S", $time); + else + $t = strftime("%Y%m%dT%H:%M:%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 index c66fd11..11e028d 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -1,536 +1,536 @@ -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 - //------------------------------------- - - 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']; - } - } - - //------------------------------------- - // Setting of System Methods - //------------------------------------- - - 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 - //------------------------------------- - - 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 - //------------------------------------- - - function add_to_map($methodname,$function,$sig,$doc) - { - $this->methods[$methodname] = array( - 'function' => $function, - 'signature' => $sig, - 'docstring' => $doc - ); - } - - - //------------------------------------- - // Parse Server Request - //------------------------------------- - - 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 - //------------------------------------- - - 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; - - //------------------------------------- - // 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 - //------------------------------------- - - 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 - //------------------------------------- - - 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 - //------------------------------------- - - 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 - //------------------------------------- - - 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 - //------------------------------------- - - 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 - //------------------------------------- - - 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 */ +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 + //------------------------------------- + + 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']; + } + } + + //------------------------------------- + // Setting of System Methods + //------------------------------------- + + 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 + //------------------------------------- + + 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 + //------------------------------------- + + function add_to_map($methodname,$function,$sig,$doc) + { + $this->methods[$methodname] = array( + 'function' => $function, + 'signature' => $sig, + 'docstring' => $doc + ); + } + + + //------------------------------------- + // Parse Server Request + //------------------------------------- + + 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 + //------------------------------------- + + 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; + + //------------------------------------- + // 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 + //------------------------------------- + + 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 + //------------------------------------- + + 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 + //------------------------------------- + + 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 + //------------------------------------- + + 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 + //------------------------------------- + + 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 + //------------------------------------- + + 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 index 8046588..1a45eb4 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -1,359 +1,359 @@ -_add_dir($dir); - } - } - - // -------------------------------------------------------------------- - - /** - * Add Directory - * - * @access private - * @param string the directory name - * @return void - */ - function _add_dir($dir) - { - $dir = str_replace("\\", "/", $dir); - - $this->zipdata .= - "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00" - .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\x00\x00\x00\x00" - .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) - { - $this->_add_data($path, $data); - } - } - else - { - $this->_add_data($filepath, $data); - } - } - - // -------------------------------------------------------------------- - - /** - * 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) - { - $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\x00\x00\x00\x00" - .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\x00\x00\x00\x00" - .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) - { - if ($fp = @opendir($path)) - { - while (FALSE !== ($file = readdir($fp))) - { - if (@is_dir($path.$file) && substr($file, 0, 1) != '.') - { - $this->read_dir($path.$file."/"); - } - elseif (substr($file, 0, 1) != ".") - { - if (FALSE !== ($data = file_get_contents($path.$file))) - { - $this->add_data(str_replace("\\", "/", $path).$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'; - } - - $zip_content =& $this->get_zip(); - - $CI =& get_instance(); - $CI->load->helper('download'); - - 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 */ +_add_dir($dir); + } + } + + // -------------------------------------------------------------------- + + /** + * Add Directory + * + * @access private + * @param string the directory name + * @return void + */ + function _add_dir($dir) + { + $dir = str_replace("\\", "/", $dir); + + $this->zipdata .= + "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00" + .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\x00\x00\x00\x00" + .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) + { + $this->_add_data($path, $data); + } + } + else + { + $this->_add_data($filepath, $data); + } + } + + // -------------------------------------------------------------------- + + /** + * 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) + { + $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\x00\x00\x00\x00" + .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\x00\x00\x00\x00" + .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) + { + if ($fp = @opendir($path)) + { + while (FALSE !== ($file = readdir($fp))) + { + if (@is_dir($path.$file) && substr($file, 0, 1) != '.') + { + $this->read_dir($path.$file."/"); + } + elseif (substr($file, 0, 1) != ".") + { + if (FALSE !== ($data = file_get_contents($path.$file))) + { + $this->add_data(str_replace("\\", "/", $path).$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'; + } + + $zip_content =& $this->get_zip(); + + $CI =& get_instance(); + $CI->load->helper('download'); + + 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 index c942a79..065d2da 100644 --- a/system/libraries/index.html +++ b/system/libraries/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

    Directory access is forbidden.

    - - + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + \ No newline at end of file diff --git a/system/logs/index.html b/system/logs/index.html index c942a79..065d2da 100644 --- a/system/logs/index.html +++ b/system/logs/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

    Directory access is forbidden.

    - - + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + \ No newline at end of file diff --git a/system/plugins/captcha_pi.php b/system/plugins/captcha_pi.php index c15bb0d..7446942 100644 --- a/system/plugins/captcha_pi.php +++ b/system/plugins/captcha_pi.php @@ -1,356 +1,356 @@ -load->plugin('captcha'); - -Once loaded you can generate a captcha like this: - - $vals = array( - 'word' => 'Random word', - 'img_path' => './captcha/', - 'img_url' => 'http://example.com/captcha/', - 'font_path' => './system/fonts/texb.ttf', - 'img_width' => '150', - 'img_height' => 30, - 'expiration' => 7200 - ); - - $cap = create_captcha($vals); - echo $cap['image']; - - -NOTES: - - The captcha function requires the GD image library. - - Only the img_path and img_url are required. - - If a "word" is not supplied, the function will generate a random - ASCII string. You might put together your own word library that - you can draw randomly from. - - If you do not specify a path to a TRUE TYPE font, the native ugly GD - font will be used. - - The "captcha" folder must be writable (666, or 777) - - The "expiration" (in seconds) signifies how long an image will - remain in the captcha folder before it will be deleted. The default - is two hours. - -RETURNED DATA - -The create_captcha() function returns an associative array with this data: - - [array] - ( - 'image' => IMAGE TAG - 'time' => TIMESTAMP (in microtime) - 'word' => CAPTCHA WORD - ) - -The "image" is the actual image tag: - - -The "time" is the micro timestamp used as the image name without the file -extension. It will be a number like this: 1139612155.3422 - -The "word" is the word that appears in the captcha image, which if not -supplied to the function, will be a random string. - - -ADDING A DATABASE - -In order for the captcha function to prevent someone from posting, you will need -to add the information returned from create_captcha() function to your database. -Then, when the data from the form is submitted by the user you will need to verify -that the data exists in the database and has not expired. - -Here is a table prototype: - - CREATE TABLE captcha ( - captcha_id bigint(13) unsigned NOT NULL auto_increment, - captcha_time int(10) unsigned NOT NULL, - ip_address varchar(16) default '0' NOT NULL, - word varchar(20) NOT NULL, - PRIMARY KEY `captcha_id` (`captcha_id`), - KEY `word` (`word`) - ) - - -Here is an example of usage with a DB. - -On the page where the captcha will be shown you'll have something like this: - - $this->load->plugin('captcha'); - $vals = array( - 'img_path' => './captcha/', - 'img_url' => 'http://example.com/captcha/' - ); - - $cap = create_captcha($vals); - - $data = array( - 'captcha_id' => '', - 'captcha_time' => $cap['time'], - 'ip_address' => $this->input->ip_address(), - 'word' => $cap['word'] - ); - - $query = $this->db->insert_string('captcha', $data); - $this->db->query($query); - - echo 'Submit the word you see below:'; - echo $cap['image']; - echo ''; - - -Then, on the page that accepts the submission you'll have something like this: - - // First, delete old captchas - $expiration = time()-7200; // Two hour limit - $DB->query("DELETE FROM captcha WHERE captcha_time < ".$expiration); - - // Then see if a captcha exists: - $sql = "SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND date > ?"; - $binds = array($_POST['captcha'], $this->input->ip_address(), $expiration); - $query = $this->db->query($sql, $binds); - $row = $query->row(); - - if ($row->count == 0) - { - echo "You must submit the word that appears in the image"; - } - -*/ - - - -/** -|========================================================== -| Create Captcha -|========================================================== -| -*/ -function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '') -{ - $defaults = array('word' => '', '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_really_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_pi.php */ +load->plugin('captcha'); + +Once loaded you can generate a captcha like this: + + $vals = array( + 'word' => 'Random word', + 'img_path' => './captcha/', + 'img_url' => 'http://example.com/captcha/', + 'font_path' => './system/fonts/texb.ttf', + 'img_width' => '150', + 'img_height' => 30, + 'expiration' => 7200 + ); + + $cap = create_captcha($vals); + echo $cap['image']; + + +NOTES: + + The captcha function requires the GD image library. + + Only the img_path and img_url are required. + + If a "word" is not supplied, the function will generate a random + ASCII string. You might put together your own word library that + you can draw randomly from. + + If you do not specify a path to a TRUE TYPE font, the native ugly GD + font will be used. + + The "captcha" folder must be writable (666, or 777) + + The "expiration" (in seconds) signifies how long an image will + remain in the captcha folder before it will be deleted. The default + is two hours. + +RETURNED DATA + +The create_captcha() function returns an associative array with this data: + + [array] + ( + 'image' => IMAGE TAG + 'time' => TIMESTAMP (in microtime) + 'word' => CAPTCHA WORD + ) + +The "image" is the actual image tag: + + +The "time" is the micro timestamp used as the image name without the file +extension. It will be a number like this: 1139612155.3422 + +The "word" is the word that appears in the captcha image, which if not +supplied to the function, will be a random string. + + +ADDING A DATABASE + +In order for the captcha function to prevent someone from posting, you will need +to add the information returned from create_captcha() function to your database. +Then, when the data from the form is submitted by the user you will need to verify +that the data exists in the database and has not expired. + +Here is a table prototype: + + CREATE TABLE captcha ( + captcha_id bigint(13) unsigned NOT NULL auto_increment, + captcha_time int(10) unsigned NOT NULL, + ip_address varchar(16) default '0' NOT NULL, + word varchar(20) NOT NULL, + PRIMARY KEY `captcha_id` (`captcha_id`), + KEY `word` (`word`) + ) + + +Here is an example of usage with a DB. + +On the page where the captcha will be shown you'll have something like this: + + $this->load->plugin('captcha'); + $vals = array( + 'img_path' => './captcha/', + 'img_url' => 'http://example.com/captcha/' + ); + + $cap = create_captcha($vals); + + $data = array( + 'captcha_id' => '', + 'captcha_time' => $cap['time'], + 'ip_address' => $this->input->ip_address(), + 'word' => $cap['word'] + ); + + $query = $this->db->insert_string('captcha', $data); + $this->db->query($query); + + echo 'Submit the word you see below:'; + echo $cap['image']; + echo ''; + + +Then, on the page that accepts the submission you'll have something like this: + + // First, delete old captchas + $expiration = time()-7200; // Two hour limit + $DB->query("DELETE FROM captcha WHERE captcha_time < ".$expiration); + + // Then see if a captcha exists: + $sql = "SELECT COUNT(*) AS count FROM captcha WHERE word = ? AND ip_address = ? AND date > ?"; + $binds = array($_POST['captcha'], $this->input->ip_address(), $expiration); + $query = $this->db->query($sql, $binds); + $row = $query->row(); + + if ($row->count == 0) + { + echo "You must submit the word that appears in the image"; + } + +*/ + + + +/** +|========================================================== +| Create Captcha +|========================================================== +| +*/ +function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '') +{ + $defaults = array('word' => '', '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_really_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_pi.php */ /* Location: ./system/plugins/captcha_pi.php */ \ No newline at end of file diff --git a/system/plugins/index.html b/system/plugins/index.html index c942a79..065d2da 100644 --- a/system/plugins/index.html +++ b/system/plugins/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

    Directory access is forbidden.

    - - + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + \ No newline at end of file diff --git a/system/plugins/js_calendar_pi.php b/system/plugins/js_calendar_pi.php index 88da72c..cde7d31 100644 --- a/system/plugins/js_calendar_pi.php +++ b/system/plugins/js_calendar_pi.php @@ -1,629 +1,629 @@ -load->plugin('js_calendar'); - -Once loaded you'll add the calendar script to the of your page like this: - - - -The above function will be passed the name of your form. - -Then to show the actual calendar you'll do this: - - -
    - -

    Today

    -
    - - -Note: The first parameter is the name of the field containing your date, the second parameter contains the "now" time, -and the third tells the calendar whether to highlight the current day or not. - -Lastly, you'll need some CSS for your calendar: - -.calendar { - border: 1px #6975A3 solid; - background-color: transparent; -} -.calheading { - background-color: #7C8BC0; - color: #fff; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - font-weight: bold; - text-align: center; -} -.calnavleft { - background-color: #7C8BC0; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 10px; - font-weight: bold; - color: #fff; - padding: 4px; - cursor: pointer; -} -.calnavright { - background-color: #7C8BC0; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 10px; - font-weight: bold; - color: #fff; - text-align: right; - padding: 4px; - cursor: pointer; -} -.caldayheading { - background-color: #000; - color: #fff; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 10px; - text-align: center; - padding: 6px 2px 6px 2px; -} -.caldaycells{ - color: #000; - background-color: #D1D7E6; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - text-align: center; - padding: 4px; - border: 1px #E0E5F1 solid; - cursor: pointer; -} -.caldaycellhover{ - color: #fff; - background-color: #B3BCD4; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - text-align: center; - padding: 4px; - border: 1px #B3BCD4 solid; - cursor: pointer; -} -.caldayselected{ - background-color: #737FAC; - color: #fff; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - font-weight: bold; - text-align: center; - border: 1px #566188 solid; - padding: 3px; - cursor: pointer; -} -.calblanktop { - background-color: #fff; - padding: 4px; -} -.calblankbot { - background-color: #fff; - padding: 4px; -} - - -*/ - -function js_calendar_script($form_name = 'entryform') -{ -$CI =& get_instance(); -$CI->load->language('calendar'); -ob_start(); -?> - - - var '.$field_id.' = new calendar("'.$field_id.'", '.$time.', '.(($highlight == TRUE) ? 'true' : 'false').'); - document.write('.$field_id.'.write()); - '; -} - - -/* End of file js_calendar_pi.php */ +load->plugin('js_calendar'); + +Once loaded you'll add the calendar script to the of your page like this: + + + +The above function will be passed the name of your form. + +Then to show the actual calendar you'll do this: + + +
    + +

    Today

    +
    + + +Note: The first parameter is the name of the field containing your date, the second parameter contains the "now" time, +and the third tells the calendar whether to highlight the current day or not. + +Lastly, you'll need some CSS for your calendar: + +.calendar { + border: 1px #6975A3 solid; + background-color: transparent; +} +.calheading { + background-color: #7C8BC0; + color: #fff; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 11px; + font-weight: bold; + text-align: center; +} +.calnavleft { + background-color: #7C8BC0; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 10px; + font-weight: bold; + color: #fff; + padding: 4px; + cursor: pointer; +} +.calnavright { + background-color: #7C8BC0; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 10px; + font-weight: bold; + color: #fff; + text-align: right; + padding: 4px; + cursor: pointer; +} +.caldayheading { + background-color: #000; + color: #fff; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 10px; + text-align: center; + padding: 6px 2px 6px 2px; +} +.caldaycells{ + color: #000; + background-color: #D1D7E6; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 11px; + text-align: center; + padding: 4px; + border: 1px #E0E5F1 solid; + cursor: pointer; +} +.caldaycellhover{ + color: #fff; + background-color: #B3BCD4; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 11px; + text-align: center; + padding: 4px; + border: 1px #B3BCD4 solid; + cursor: pointer; +} +.caldayselected{ + background-color: #737FAC; + color: #fff; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 11px; + font-weight: bold; + text-align: center; + border: 1px #566188 solid; + padding: 3px; + cursor: pointer; +} +.calblanktop { + background-color: #fff; + padding: 4px; +} +.calblankbot { + background-color: #fff; + padding: 4px; +} + + +*/ + +function js_calendar_script($form_name = 'entryform') +{ +$CI =& get_instance(); +$CI->load->language('calendar'); +ob_start(); +?> + + + var '.$field_id.' = new calendar("'.$field_id.'", '.$time.', '.(($highlight == TRUE) ? 'true' : 'false').'); + document.write('.$field_id.'.write()); + '; +} + + +/* End of file js_calendar_pi.php */ /* Location: ./system/plugins/js_calendar_pi.php */ \ No newline at end of file diff --git a/system/scaffolding/Scaffolding.php b/system/scaffolding/Scaffolding.php index 72b9b09..2c72e88 100644 --- a/system/scaffolding/Scaffolding.php +++ b/system/scaffolding/Scaffolding.php @@ -1,291 +1,291 @@ -CI =& get_instance(); - - $this->CI->load->database("", FALSE, TRUE); - $this->CI->load->library('pagination'); - - // Turn off caching - $this->CI->db->cache_off(); - - /** - * Set the current table name - * This is done when initializing scaffolding: - * $this->load->scaffolding('table_name') - * - */ - $this->current_table = $db_table; - - /** - * Set the path to the "view" files - * We'll manually override the "view" path so that - * the load->view function knows where to look. - */ - - $this->CI->load->_ci_view_path = BASEPATH.'scaffolding/views/'; - - // Set the base URL - $this->base_url = $this->CI->config->site_url().'/'.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, 'both'); - $this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, 'leading'); - - // Set a few globals - $data = array( - 'image_url' => $this->CI->config->system_url().'scaffolding/images/', - 'base_uri' => $this->base_uri, - 'base_url' => $this->base_url, - 'title' => $this->current_table - ); - - $this->CI->load->vars($data); - - // Load the language file and create variables - $this->lang = $this->CI->load->scaffold_language('scaffolding', '', TRUE); - $this->CI->load->vars($this->lang); - - // Load the helper files we plan to use - $this->CI->load->helper(array('url', 'form')); - - - log_message('debug', 'Scaffolding Class Initialized'); - } - - // -------------------------------------------------------------------- - - /** - * "Add" Page - * - * Shows a form representing the currently selected DB - * so that data can be inserted - * - * @access public - * @return string the HTML "add" page - */ - function add() - { - $data = array( - 'title' => ( ! isset($this->lang['scaff_add'])) ? 'Add Data' : $this->lang['scaff_add'], - 'fields' => $this->CI->db->field_data($this->current_table), - 'action' => $this->base_uri.'/insert' - ); - - $this->CI->load->view('add', $data); - } - - // -------------------------------------------------------------------- - - /** - * Insert the data - * - * @access public - * @return void redirects to the view page - */ - function insert() - { - if ($this->CI->db->insert($this->current_table, $_POST) === FALSE) - { - $this->add(); - } - else - { - redirect($this->base_uri.'/view/'); - } - } - - // -------------------------------------------------------------------- - - /** - * "View" Page - * - * Shows a table containing the data in the currently - * selected DB - * - * @access public - * @return string the HTML "view" page - */ - function view() - { - // Fetch the total number of DB rows - $total_rows = $this->CI->db->count_all($this->current_table); - - if ($total_rows < 1) - { - return $this->CI->load->view('no_data'); - } - - // Set the query limit/offset - $per_page = 20; - $offset = $this->CI->uri->segment(4, 0); - - // Run the query - $query = $this->CI->db->get($this->current_table, $per_page, $offset); - - // Now let's get the field names - $fields = $this->CI->db->list_fields($this->current_table); - - // We assume that the column in the first position is the primary field. - $primary = current($fields); - - // Pagination! - $this->CI->pagination->initialize( - array( - 'base_url' => $this->base_url.'/view', - 'total_rows' => $total_rows, - 'per_page' => $per_page, - 'uri_segment' => 4, - 'full_tag_open' => '

    ', - 'full_tag_close' => '

    ' - ) - ); - - $data = array( - 'title' => ( ! isset($this->lang['scaff_view'])) ? 'View Data' : $this->lang['scaff_view'], - 'query' => $query, - 'fields' => $fields, - 'primary' => $primary, - 'paginate' => $this->CI->pagination->create_links() - ); - - $this->CI->load->view('view', $data); - } - - // -------------------------------------------------------------------- - - /** - * "Edit" Page - * - * Shows a form representing the currently selected DB - * so that data can be edited - * - * @access public - * @return string the HTML "edit" page - */ - function edit() - { - if (FALSE === ($id = $this->CI->uri->segment(4))) - { - return $this->view(); - } - - // Fetch the primary field name - $primary = $this->CI->db->primary($this->current_table); - - // Run the query - $query = $this->CI->db->get_where($this->current_table, array($primary => $id)); - - $data = array( - 'title' => ( ! isset($this->lang['scaff_edit'])) ? 'Edit Data' : $this->lang['scaff_edit'], - 'fields' => $query->field_data(), - 'query' => $query->row(), - 'action' => $this->base_uri.'/update/'.$this->CI->uri->segment(4) - ); - - $this->CI->load->view('edit', $data); - } - - // -------------------------------------------------------------------- - - /** - * Update - * - * @access public - * @return void redirects to the view page - */ - function update() - { - // Fetch the primary key - $primary = $this->CI->db->primary($this->current_table); - - // Now do the query - $this->CI->db->update($this->current_table, $_POST, array($primary => $this->CI->uri->segment(4))); - - redirect($this->base_uri.'/view/'); - } - - // -------------------------------------------------------------------- - - /** - * Delete Confirmation - * - * @access public - * @return string the HTML "delete confirm" page - */ - function delete() - { - if ( ! isset($this->lang['scaff_del_confirm'])) - { - $message = 'Are you sure you want to delete the following row: '.$this->CI->uri->segment(4); - } - else - { - $message = $this->lang['scaff_del_confirm'].' '.$this->CI->uri->segment(4); - } - - $data = array( - 'title' => ( ! isset($this->lang['scaff_delete'])) ? 'Delete Data' : $this->lang['scaff_delete'], - 'message' => $message, - 'no' => anchor(array($this->base_uri, 'view'), ( ! isset($this->lang['scaff_no'])) ? 'No' : $this->lang['scaff_no']), - 'yes' => anchor(array($this->base_uri, 'do_delete', $this->CI->uri->segment(4)), ( ! isset($this->lang['scaff_yes'])) ? 'Yes' : $this->lang['scaff_yes']) - ); - - $this->CI->load->view('delete', $data); - } - - // -------------------------------------------------------------------- - - /** - * Delete - * - * @access public - * @return void redirects to the view page - */ - function do_delete() - { - // Fetch the primary key - $primary = $this->CI->db->primary($this->current_table); - - // Now do the query - $this->CI->db->where($primary, $this->CI->uri->segment(4)); - $this->CI->db->delete($this->current_table); - - header("Refresh:0;url=".site_url(array($this->base_uri, 'view'))); - exit; - } - -} - -/* End of file Scaffolding.php */ +CI =& get_instance(); + + $this->CI->load->database("", FALSE, TRUE); + $this->CI->load->library('pagination'); + + // Turn off caching + $this->CI->db->cache_off(); + + /** + * Set the current table name + * This is done when initializing scaffolding: + * $this->load->scaffolding('table_name') + * + */ + $this->current_table = $db_table; + + /** + * Set the path to the "view" files + * We'll manually override the "view" path so that + * the load->view function knows where to look. + */ + + $this->CI->load->_ci_view_path = BASEPATH.'scaffolding/views/'; + + // Set the base URL + $this->base_url = $this->CI->config->site_url().'/'.$this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, 'both'); + $this->base_uri = $this->CI->uri->segment(1).$this->CI->uri->slash_segment(2, 'leading'); + + // Set a few globals + $data = array( + 'image_url' => $this->CI->config->system_url().'scaffolding/images/', + 'base_uri' => $this->base_uri, + 'base_url' => $this->base_url, + 'title' => $this->current_table + ); + + $this->CI->load->vars($data); + + // Load the language file and create variables + $this->lang = $this->CI->load->scaffold_language('scaffolding', '', TRUE); + $this->CI->load->vars($this->lang); + + // Load the helper files we plan to use + $this->CI->load->helper(array('url', 'form')); + + + log_message('debug', 'Scaffolding Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * "Add" Page + * + * Shows a form representing the currently selected DB + * so that data can be inserted + * + * @access public + * @return string the HTML "add" page + */ + function add() + { + $data = array( + 'title' => ( ! isset($this->lang['scaff_add'])) ? 'Add Data' : $this->lang['scaff_add'], + 'fields' => $this->CI->db->field_data($this->current_table), + 'action' => $this->base_uri.'/insert' + ); + + $this->CI->load->view('add', $data); + } + + // -------------------------------------------------------------------- + + /** + * Insert the data + * + * @access public + * @return void redirects to the view page + */ + function insert() + { + if ($this->CI->db->insert($this->current_table, $_POST) === FALSE) + { + $this->add(); + } + else + { + redirect($this->base_uri.'/view/'); + } + } + + // -------------------------------------------------------------------- + + /** + * "View" Page + * + * Shows a table containing the data in the currently + * selected DB + * + * @access public + * @return string the HTML "view" page + */ + function view() + { + // Fetch the total number of DB rows + $total_rows = $this->CI->db->count_all($this->current_table); + + if ($total_rows < 1) + { + return $this->CI->load->view('no_data'); + } + + // Set the query limit/offset + $per_page = 20; + $offset = $this->CI->uri->segment(4, 0); + + // Run the query + $query = $this->CI->db->get($this->current_table, $per_page, $offset); + + // Now let's get the field names + $fields = $this->CI->db->list_fields($this->current_table); + + // We assume that the column in the first position is the primary field. + $primary = current($fields); + + // Pagination! + $this->CI->pagination->initialize( + array( + 'base_url' => $this->base_url.'/view', + 'total_rows' => $total_rows, + 'per_page' => $per_page, + 'uri_segment' => 4, + 'full_tag_open' => '

    ', + 'full_tag_close' => '

    ' + ) + ); + + $data = array( + 'title' => ( ! isset($this->lang['scaff_view'])) ? 'View Data' : $this->lang['scaff_view'], + 'query' => $query, + 'fields' => $fields, + 'primary' => $primary, + 'paginate' => $this->CI->pagination->create_links() + ); + + $this->CI->load->view('view', $data); + } + + // -------------------------------------------------------------------- + + /** + * "Edit" Page + * + * Shows a form representing the currently selected DB + * so that data can be edited + * + * @access public + * @return string the HTML "edit" page + */ + function edit() + { + if (FALSE === ($id = $this->CI->uri->segment(4))) + { + return $this->view(); + } + + // Fetch the primary field name + $primary = $this->CI->db->primary($this->current_table); + + // Run the query + $query = $this->CI->db->get_where($this->current_table, array($primary => $id)); + + $data = array( + 'title' => ( ! isset($this->lang['scaff_edit'])) ? 'Edit Data' : $this->lang['scaff_edit'], + 'fields' => $query->field_data(), + 'query' => $query->row(), + 'action' => $this->base_uri.'/update/'.$this->CI->uri->segment(4) + ); + + $this->CI->load->view('edit', $data); + } + + // -------------------------------------------------------------------- + + /** + * Update + * + * @access public + * @return void redirects to the view page + */ + function update() + { + // Fetch the primary key + $primary = $this->CI->db->primary($this->current_table); + + // Now do the query + $this->CI->db->update($this->current_table, $_POST, array($primary => $this->CI->uri->segment(4))); + + redirect($this->base_uri.'/view/'); + } + + // -------------------------------------------------------------------- + + /** + * Delete Confirmation + * + * @access public + * @return string the HTML "delete confirm" page + */ + function delete() + { + if ( ! isset($this->lang['scaff_del_confirm'])) + { + $message = 'Are you sure you want to delete the following row: '.$this->CI->uri->segment(4); + } + else + { + $message = $this->lang['scaff_del_confirm'].' '.$this->CI->uri->segment(4); + } + + $data = array( + 'title' => ( ! isset($this->lang['scaff_delete'])) ? 'Delete Data' : $this->lang['scaff_delete'], + 'message' => $message, + 'no' => anchor(array($this->base_uri, 'view'), ( ! isset($this->lang['scaff_no'])) ? 'No' : $this->lang['scaff_no']), + 'yes' => anchor(array($this->base_uri, 'do_delete', $this->CI->uri->segment(4)), ( ! isset($this->lang['scaff_yes'])) ? 'Yes' : $this->lang['scaff_yes']) + ); + + $this->CI->load->view('delete', $data); + } + + // -------------------------------------------------------------------- + + /** + * Delete + * + * @access public + * @return void redirects to the view page + */ + function do_delete() + { + // Fetch the primary key + $primary = $this->CI->db->primary($this->current_table); + + // Now do the query + $this->CI->db->where($primary, $this->CI->uri->segment(4)); + $this->CI->db->delete($this->current_table); + + header("Refresh:0;url=".site_url(array($this->base_uri, 'view'))); + exit; + } + +} + +/* End of file Scaffolding.php */ /* Location: ./system/scaffolding/Scaffolding.php */ \ No newline at end of file diff --git a/system/scaffolding/images/index.html b/system/scaffolding/images/index.html index c942a79..065d2da 100644 --- a/system/scaffolding/images/index.html +++ b/system/scaffolding/images/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

    Directory access is forbidden.

    - - + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + \ No newline at end of file diff --git a/system/scaffolding/index.html b/system/scaffolding/index.html index c942a79..065d2da 100644 --- a/system/scaffolding/index.html +++ b/system/scaffolding/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

    Directory access is forbidden.

    - - + + + 403 Forbidden + + + +

    Directory access is forbidden.

    + + \ No newline at end of file diff --git a/system/scaffolding/views/add.php b/system/scaffolding/views/add.php index de20cb8..933e127 100644 --- a/system/scaffolding/views/add.php +++ b/system/scaffolding/views/add.php @@ -1,32 +1,32 @@ -load->view('header'); ?> - -

    - - - - - - - -primary_key == 1) continue; ?> - - - - - type == 'blob'): ?> - - - - - - - -
    name; echo ' '.$field->default; ?>
    - - - - - -load->view('footer'); -/* End of file add.php */ -/* Location: ./system/scaffolding/views/add.php */ +load->view('header'); ?> + +

    + + + + + + + +primary_key == 1) continue; ?> + + + + + type == 'blob'): ?> + + + + + + + +
    name; echo ' '.$field->default; ?>
    + + + + + +load->view('footer'); +/* End of file add.php */ +/* Location: ./system/scaffolding/views/add.php */ diff --git a/system/scaffolding/views/delete.php b/system/scaffolding/views/delete.php index dc0aaed..7e962fa 100644 --- a/system/scaffolding/views/delete.php +++ b/system/scaffolding/views/delete.php @@ -1,9 +1,9 @@ -load->view('header'); ?> - -

    - -

      |   - -load->view('footer'); -/* End of file delete.php */ -/* Location: ./system/scaffolding/views/delete.php */ +load->view('header'); ?> + +

    + +

      |   + +load->view('footer'); +/* End of file delete.php */ +/* Location: ./system/scaffolding/views/delete.php */ diff --git a/system/scaffolding/views/edit.php b/system/scaffolding/views/edit.php index 810e9de..b402773 100644 --- a/system/scaffolding/views/edit.php +++ b/system/scaffolding/views/edit.php @@ -1,33 +1,33 @@ -load->view('header'); ?> - - -

    - - - - - - - -primary_key == 1) continue; ?> - - - - - type == 'blob'): ?> - - - - - - - -
    name; ?>
    - - - - - -load->view('footer'); -/* End of file edit.php */ +load->view('header'); ?> + + +

    + + + + + + + +primary_key == 1) continue; ?> + + + + + type == 'blob'): ?> + + + + + + + +
    name; ?>
    + + + + + +load->view('footer'); +/* End of file edit.php */ /* Location: ./system/scaffolding/views/edit.php */ \ No newline at end of file diff --git a/system/scaffolding/views/footer.php b/system/scaffolding/views/footer.php index 0e71401..a287664 100644 --- a/system/scaffolding/views/footer.php +++ b/system/scaffolding/views/footer.php @@ -1,10 +1,10 @@ - -
    - - - - + +
+ + + + \ No newline at end of file diff --git a/system/scaffolding/views/header.php b/system/scaffolding/views/header.php index 50f234a..a1621ff 100644 --- a/system/scaffolding/views/header.php +++ b/system/scaffolding/views/header.php @@ -1,29 +1,29 @@ - - - - -<?php echo $title; ?> - - - - - - - - - - - - -
+ + + + +<?php echo $title; ?> + + + + + + + + + + + + +
\ No newline at end of file diff --git a/system/scaffolding/views/index.html b/system/scaffolding/views/index.html index c942a79..065d2da 100644 --- a/system/scaffolding/views/index.html +++ b/system/scaffolding/views/index.html @@ -1,10 +1,10 @@ - - - 403 Forbidden - - - -

Directory access is forbidden.

- - + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + \ No newline at end of file diff --git a/system/scaffolding/views/no_data.php b/system/scaffolding/views/no_data.php index b690acd..7fc73ae 100644 --- a/system/scaffolding/views/no_data.php +++ b/system/scaffolding/views/no_data.php @@ -1,8 +1,8 @@ -load->view('header'); ?> - -

-

- -load->view('footer'); -/* End of file no_data.php */ +load->view('header'); ?> + +

+

+ +load->view('footer'); +/* End of file no_data.php */ /* Location: ./system/scaffolding/views/no_data.php */ \ No newline at end of file diff --git a/system/scaffolding/views/stylesheet.css b/system/scaffolding/views/stylesheet.css index 3f487dd..ba6ee0a 100644 --- a/system/scaffolding/views/stylesheet.css +++ b/system/scaffolding/views/stylesheet.css @@ -1,143 +1,143 @@ -body { - margin: 0; - padding: 0; - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - color: #4F5155; - background: #fff url(background.jpg) repeat-x left top; -} - -a { - color: #8B0D00; - background-color: transparent; - text-decoration: none; - font-weight: bold; -} - -a:visited { - color: #8B0D00; - background-color: transparent; - text-decoration: none; -} - -a:hover { - color: #000; - text-decoration: none; - background-color: transparent; -} - - -#header { - margin: 0; - padding: 0; -} - -#header_left { - background-color: transparent; - float: left; - padding: 21px 0 0 32px; - margin: 0 -} - -#header_right { - background-color: transparent; - float: right; - text-align: right; - padding: 35px 50px 20px 0; - margin: 0 -} - -#footer { - margin: 20px 0 15px 0; - padding: 0; -} - -#footer p { - font-size: 10px; - color: #999; - text-align: center; -} - -#outer { - margin: 30px 40px 0 40px; -} - -img { - padding:0; - border: 0; - margin: 0; -} - -.nopad { - padding:0; - border: 0; - margin: 0; -} - -table { - background-color: #efefef; -} - -th { - background-color: #eee; - font-weight: bold; - padding: 6px; - text-align: left; -} - -td { - background-color: #fff; - padding: 6px; -} - - -form { - margin: 0; - padding: 0; -} - -.input { - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 11px; - width: 600px; - color: #333; - border: 1px solid #B3B4BD; - font-size: 11px; - height: 2em; - padding: 0; - margin: 0; -} - -.textarea { - font-family: Lucida Grande, Verdana, Geneva, Sans-serif; - font-size: 12px; - width: 600px; - color: #333; - border: 1px solid #B3B4BD; - padding: 0; - margin: 0; -} - -.select { - background-color: #fff; - font-size: 11px; - font-weight: normal; - color: #333; - padding: 0; - margin: 0 0 3px 0; -} - -.checkbox { - background-color: transparent; - padding: 0; - border: 0; -} - -.submit { - background-color: #8B0D00; - color: #FFF; - font-weight: normal; - border: 1px solid #000; - margin: 6px 0 0 0; - padding: 1px 5px 1px 5px; -} +body { + margin: 0; + padding: 0; + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 11px; + color: #4F5155; + background: #fff url(background.jpg) repeat-x left top; +} + +a { + color: #8B0D00; + background-color: transparent; + text-decoration: none; + font-weight: bold; +} + +a:visited { + color: #8B0D00; + background-color: transparent; + text-decoration: none; +} + +a:hover { + color: #000; + text-decoration: none; + background-color: transparent; +} + + +#header { + margin: 0; + padding: 0; +} + +#header_left { + background-color: transparent; + float: left; + padding: 21px 0 0 32px; + margin: 0 +} + +#header_right { + background-color: transparent; + float: right; + text-align: right; + padding: 35px 50px 20px 0; + margin: 0 +} + +#footer { + margin: 20px 0 15px 0; + padding: 0; +} + +#footer p { + font-size: 10px; + color: #999; + text-align: center; +} + +#outer { + margin: 30px 40px 0 40px; +} + +img { + padding:0; + border: 0; + margin: 0; +} + +.nopad { + padding:0; + border: 0; + margin: 0; +} + +table { + background-color: #efefef; +} + +th { + background-color: #eee; + font-weight: bold; + padding: 6px; + text-align: left; +} + +td { + background-color: #fff; + padding: 6px; +} + + +form { + margin: 0; + padding: 0; +} + +.input { + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 11px; + width: 600px; + color: #333; + border: 1px solid #B3B4BD; + font-size: 11px; + height: 2em; + padding: 0; + margin: 0; +} + +.textarea { + font-family: Lucida Grande, Verdana, Geneva, Sans-serif; + font-size: 12px; + width: 600px; + color: #333; + border: 1px solid #B3B4BD; + padding: 0; + margin: 0; +} + +.select { + background-color: #fff; + font-size: 11px; + font-weight: normal; + color: #333; + padding: 0; + margin: 0 0 3px 0; +} + +.checkbox { + background-color: transparent; + padding: 0; + border: 0; +} + +.submit { + background-color: #8B0D00; + color: #FFF; + font-weight: normal; + border: 1px solid #000; + margin: 6px 0 0 0; + padding: 1px 5px 1px 5px; +} diff --git a/system/scaffolding/views/view.php b/system/scaffolding/views/view.php index 7839022..677fbff 100644 --- a/system/scaffolding/views/view.php +++ b/system/scaffolding/views/view.php @@ -1,27 +1,27 @@ -load->view('header'); ?> - - - - - - - - - - -result() as $row): ?> - - - - - - - - -
EditDelete
 $primary), $scaff_edit); ?> $primary), $scaff_delete); ?>$field);?>
- - - -load->view('footer'); -/* End of file view.php */ +load->view('header'); ?> + + + + + + + + + + +result() as $row): ?> + + + + + + + + +
EditDelete
 $primary), $scaff_edit); ?> $primary), $scaff_delete); ?>$field);?>
+ + + +load->view('footer'); +/* End of file view.php */ /* Location: ./system/scaffolding/views/view.php */ \ No newline at end of file diff --git a/update-translations.sh b/update-translations.sh new file mode 100644 index 0000000..df7d7e7 --- /dev/null +++ b/update-translations.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +#write all php files in file +(find ./data -name "*.php" && find ./system -name "*.php") > update-translations.txt + +#call xgettext to create pot file +xgettext -f update-translations.txt -kT_ngettext:1,2 -kT_ --language=PHP -o update-translations.pot