diff --git a/wmglobe/CHANGES b/wmglobe/CHANGES new file mode 100644 index 0000000..d7f0554 --- /dev/null +++ b/wmglobe/CHANGES @@ -0,0 +1,45 @@ +VMGlobe +0.5 released 6/02/99 + - floating point exception bug solved + - many minor bugs solved (earth displaying, mouse, time management) + - compile time options in header + - night map option available in parameter screen + - option -time only available in command line + - new default map + +0.5.pre1 released 20/01/99 + - option selection through parameters screens (right button) + - approximation of date & time of view point + - new default map (bigger, better) + - display of time uses setlocale() + - option -dawn value : enhance dawn borderline + - option -time : change date displayed + - option -nonimap + - reorganize sources, little CPU gain, better earth displaying + - rename -austral to -oz + - modify comportment of -rand option when zooming + - change left button comportment : only change longitude + - shift+left button : change longitude & latitude + - man page + +0.3.1 released 5/02/99 + - option -austral + - solved bug about colors 24 and 32 bit per pixel + +0.3 released 3/02/99 + - right button : screen of digital modification of latitude/long. + +0.2.1 released 3/02/99 + - change & enhance mouse operations (longitude/latitude/zoom) + - minor bugs, CPU optimization + +0.2 released 1/01/99 + - bug about ipc & shared memory solved. + - new functionnality : + left click = change longitude + middle click = zoom in / zoom out + right click = change latitude + - a few hints for compile on *BSD + +0.1 released 31/12/98 + diff --git a/wmglobe/COPYING b/wmglobe/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/wmglobe/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 + + Appendix: 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) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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/wmglobe/Makefile b/wmglobe/Makefile new file mode 100644 index 0000000..b619240 --- /dev/null +++ b/wmglobe/Makefile @@ -0,0 +1,22 @@ +INC = -I/usr/X11R6/include +LIBS = -lXext -lX11 -lm -L/usr/X11R6/lib \ + -ltiff -lXpm -lpng -lz -ljpeg -lungif -lwraster +OBJS = src/wmglobe.o src/rend.o src/wmgutil.o \ + src/sunpos.o src/myconvert.o src/mycontext.o + + +.c.o : + gcc -c -O2 -Wall $(INC) $< -o $*.o + +all: wmglobe + +clean: + rm -f src/*.o wmglobe + +wmglobe : $(OBJS) + gcc -O2 -Wall $(OBJS) -o wmglobe $(LIBS) + strip wmglobe + +install : + install wmglobe /usr/local/bin + install wmglobe.1 /usr/local/man/man1 diff --git a/wmglobe/README b/wmglobe/README new file mode 100644 index 0000000..1b6370e --- /dev/null +++ b/wmglobe/README @@ -0,0 +1,349 @@ +WMGlobe 0.5 - The Whole Earth spinning on you desktop... as a dockable app +Copyright (C) 1998,99 Jerome Dumonteil +This program is licensed under the terms of the GNU GPL, see below. + + + +Description +---------------------------------------- +WMGlobe is a WindowMaker dock.app that displays the earth on an icon. It's +an adaptation of XGlobe to WMaker environnement. WMGlobe uses a map which is +rendered on a sphere by raytracing. Yes, for a 64x64 pixel result :-) + +It's still a beta version... + + + +Installation +---------------------------------------- +You need WindowMaker to build WMGlobe. WMGlobe needs libwraster to compile, +this lib is built by WindowMaker. No more need at run time if statically +linked, but then, you need WindowMaker to get the full magic :-) + + + tar -xvzf wmglobe-0.5.tar.gz + cd wmglobe-0.5 + make + + then move wmglobe in /usr/local/bin and man page somewhere or do + (as root) : + make install + + +If it doesn't work, look for the graphic libraries. + +The Makefile is quite crude... + +WMGlobe is developped on Linux (WMaker 0.51.0 and linux 2.0.36/ix86). +If you are successful on other platforms, please tell me so. + + +platforms with successfull built reported : + +NetBSD 1.3.2 / SPARC (wmaker 0.20.3) , with Makefile adaptations for libs +Linux 2.0.36 / RedHat 5.1 +Linux 2.0.36 / SuSE 5.3 (wmaker 0.20.3) , -lungif -> -lgif +Linux 2.2.0-pre4 / Debian :-) +FreeBSD-3.0 with -ltiff -> -ltiff34 and -lungif -> -lgif +Solaris 2.6 / Sun Sparc (wmaker 0.20.3) , with Makefile adaptations for libs +AIX 4.2.1 / IBM RS/6000-250 (wmaker 0.50.2) + + + +RPM & DEBIAN linux packages coming soon. Or you can directly use the binary. + +compile time problems : + +Xlib.h, Xpm.h ... : +If you compile wmglobe on a computer installed with packages (.rpm), you may +lack of these header files. Just install the "xxx-dev.rpm" packages for XFree86 +and graphics libs, or install a rpm version of wmglobe. + +libwraster : +WindowMaker 0.20.3 uses a libwraster.a , so if you use it, you can execute +the binary on a computer without WindowMaker on it, and displaying on a +remote computer (this one using WindowMaker). WM 0.51.0 creates a dynamic +libwraster.so, so it's necessary to have it on the computer running wmglobe +if you buit WMGlobe with this one. Both versions of WMGlobe run on WM 0.20.3 +and 0.51.0 + +graphic libs : +you can use libgif or libungif. If your version of WindowMaker is built +without support for some graphic type, you don't need it (just remove it +from the makefile). +This problem may happen with RedHat 5.2, if you get this kind of message, +just add a libtiff to your system : +/usr/local/lib/libwraster.so: undefined reference to `TIFFReadDirectory' +... +make: *** [wmglobe] Error 1 + + +compile time options : +You can modify the file wmgoption.h where many options are set up in defines : + +To disable the builtin default map, just comment out the line in wmgoptions.h : +#define DEFMAPOK +to supprim the shift+left/left method of rotate earth, uncomment the lines +#define MOUSE_LAT_FULL + +you can also suppress some options screen in wmgoption.h + + + +Maps +---------------------------------------- +Like XGlobe, WMGlobe needs a longitude/latitude map to work. By default, +it uses a low quality built-in map of earth. But you will probably want +to use better ones. + +You can get maps usable with WMGlobe on the net. See the LINKS chapter. + +using custom maps : +- For the image to be mapped correctly, position 0°North 0°West must be in + the center of the image and the latitude must be linear from 90°N to 90°S. +- When using a night map, make sure that day and night map have the same + dimensions. + +By the way, you can use maps of Mars, Luna ... and text. + + + +Configuration options +---------------------------------------- + +Configuration is done through command line options. + +-v version +-h short help + +-zoom zoom_value Value > 1 to magnify the view, value < 1 to lower. + Default : 1.0 + +-pos latitude long. Initial viewing fixed at this position, don't follow + the sun rotation. Accepted values in the form + 45°12'36 or 45.21 or 45:12:36 + Default : the initial position is "under" the sun, and + the point of view follows the sun + +-rand New random position at every refresh of screen + +-map map_file Map used for the rendering. Can be JPEG, GIG, XPM + PNM, TIFF but none BMP + Default : use internal map of earth. + +-nimap night_file Map used for the dark side of the earth. Must be of + the same width x height as the day side map. + Default : if the default internal day map is used, use + a default internal night file (see -nonimap option). + If a custom day map is provided, and no night map, the + dark side is computed via the -light option. + +-nonimap Don't use the default night map. + +-delay seconds Time in seconds between each calculation of a new + position. Limited to 0.04 at compile time (25 frames + per second should be enough). The sun position move + only once per minute, so if you use wmglobe without + -dlong or -accel option, the CPU cost of WMGlobe is + *very* low. The use of very low value for -delay plus + -dlong and -accel can be CPU costly (but very nice...) + Default : 1.0 sec. + +-dlat delta_latitude Move the point of view by delta_lat degrees per second, + with a value of 6 the earth make a full rotation in + one minute. The value can be formated as -pos option. + Default : 0°0'0 + +-dlong delta_long Move the point of view by delta_long degrees per + second. With a value of -0°0'15" the earth make a full + rotation in 24 hours toward the west. By default, + -dlong and -dlat are null. If they are used, the view + follow their values. Going back to "follow sun" mode + in parameters screen put -dlat and -dlong to zero. + +-light light_value Level of light of the dark side when there is no + night map, from 0 to 1. + Default : 0.25 + +-dawn dawn_value Level of continuity for dawn limit, from 0 to 1. With + a value of 1, the border line between night and day is + at maximum contrast. + Default : 0.2 + +-bord border_num 0 1 or 2. There are 3 different borders for the icon. + Default : 0 + +-accel time_multi Time warp factor. With -accel 24, the sun make a full + rotation in one hour (or the earth, I'm not sure). + Default : 1.0 + +-time seconds Time to display in seconds since 01-01-1970 (see the + date command). Necessary if you need to be sure that + WMGlobe is Y2K compliant without changing system time. + Negative values for dates before 1970 accepted. + Default : not set, use current time. + +-fun dx dy Move the earth image by dx dy pixels in the icon. See + puzzle.sh to understand why. + +-oz Start in "austral" mode (for "down under" people) + +-d display Select another display + +-w -shape Useless, since it is set by default (WMaker dockable + application) + +mouse : +left button Change longitude while pressed, change longitude & + latitude if shift+left button. + +middle button Zoom in, shift + middle button : zoom out + +right button Displays 7 screens of parameters. On every screen, just + clic with left or right button on the figures to change + their value. The TIME screen shows an approximation + of date and time of the earth zone currently displayed, + using GMT time + longitude offset, it's close to the + real local time by one or two hours. Others options + don't need more help. Intuitive they said... + + + +Links : Some sites dealing with WindowMaker +------------------------------------------- + +Official Window Maker Website : +http://www.windowmaker.org/ + +The Dock App Warehouse : +http://www.bensinclair.com/dockapp/ + + + +Links : Where to find maps and similar softs +-------------------------------------------- +where to find the sources of wmglobe : +http://www.capway.com/dumonte1/wm/wmglobe-0.5.tar.gz + +the web page of WMGlobe (made by Sylvestre Taburet) : +http://www.capway.com/dumonte1/wm/wmg.html + + +where to find maps and similar softs : + +Earth image by a cgi : +http://www.fourmilab.ch/cgi-bin/uncgi/Earth + +two softs running under X : +XGlobe Homepage: http://www.uni-karlsruhe.de/~uddn/xglobe +(the recent 0.2 version brings a very nice map of earth) + +Xearth Homepage: http://www.cs.colorado.edu/~tuna/xearth/ + + +For the maps XGlobe doc says : + +« WHERE TO GET MAPS: + +1. LivingEarth Inc. + +http://livingearth.com/LE/LivEarthImg.html +http://livingearth.com/LE/BrillEarthImg.html + +Livingearth Inc. has some nice (day and night) images on their web pages. +With these you can test the -nightmap option of XEarth. Unfortunately +they are pretty low-res (400x200). +You can find a higher-resolution (but heavily compressed) version of this +day map at the "Earth View" page: + +http://www.fourmilab.ch/cgi-bin/uncgi/Earth + +Check "No night" and set display to "map", then save the image. + + +2. NOAA NGDC Marine Geology & Geophysics + +http://www.ngdc.noaa.gov:80/mgg/image/mggd.gif + +This image is definitely not "photo-realistic" but nonetheless pretty +interesting. It also has a rather high resolution. » + + + +Todo +---------------------------------------- +- test on different platforms, better makefile +- changing map "on the fly", map generator, clouds generator... +- must work on every current WindowMaker platform +- see how to minimize CPU load +- feature : load a local detailed map of some part of the globe when zooming + (country maps, city maps) +- maybe port to other window manager + + + +Bugs +---------------------------------------- +- The Makefile +- if you use the --enable-single-icon compile time option of WindowMaker, + you can not display more than one WMGlobe. +- WMGlobe hopes that an overflow of a long integer dont generate an error + and that LONG_MAX +1 = LONG_MIN . This happens with high values of -accel + when the date go over year 2038. The expected result is wmglobe + continuing smoothly from 1901. + + + +License +---------------------------------------- +WMGlobe is Copyright (C) 1998,99 by Jerome Dumonteil and licensed through +the GNU General Public License. +Read the COPYING file for the complete GNU license. + + + +Credits +---------------------------------------- +Original idea, tests, logos : Sylvestre Taburet + +The code in 'sunpos.cpp' is taken from Xearth by Kirk Lauritz Johnson. + +/* + * sunpos.c + * kirk johnson + * july 1993 + * + * code for calculating the position on the earth's surface for which + * the sun is directly overhead (adapted from _practical astronomy + * with your calculator, third edition_, peter duffett-smith, + * cambridge university press, 1988.) + * + * + * Copyright (C) 1989, 1990, 1993, 1994, 1995 Kirk Lauritz Johnson + * + * Parts of the source code (as marked) are: + * Copyright (C) 1989, 1990, 1991 by Jim Frost + * Copyright (C) 1992 by Jamie Zawinski + * + * Permission to use, copy, modify and freely distribute xearth for + * non-commercial and not-for-profit purposes is hereby granted + * without fee, provided that both the above copyright notice and this + * permission notice appear in all copies and in supporting + * documentation. + */ + +The rendering engine is taken from XGlobe by Thorsten Scheuermann +XGlobe Homepage: http://www.uni-karlsruhe.de/~uddn/xglobe + +Raster graphics library by Alfredo K. Kojima, & stuff of Window Maker + by A. K. Kojima, Dan Pascu, Matthew Hawkins & team + + + +Feedback +---------------------------------------- +For your questions, bugs, remarks, please contact our representative on +planet Earth : jerome dumonteil + + + diff --git a/wmglobe/puzzle.sh b/wmglobe/puzzle.sh new file mode 100755 index 0000000..1fd1ddd --- /dev/null +++ b/wmglobe/puzzle.sh @@ -0,0 +1,17 @@ +#!/bin/sh +#just for the fun, solve the puzzle and put it on the clip :) + +if [ -x ./wmglobe ] +then +WMG="nice ./wmglobe" +else +WMG="nice wmglobe" +fi + +HOP=" -delay 0.1 -pos -25 10 -dlat 0.5 -dlong -5 -zoom 1.8 -accel 240" + +$WMG $HOP -fun 32 32 & +$WMG $HOP -fun -32 32 & +$WMG $HOP -fun 32 -32 & +$WMG $HOP -fun -32 -32 & +$WMG -map ./wmgmap.gif -delay 0.05 -dlong 25 -pos 0 0 -accel 10000& diff --git a/wmglobe/src/cadre0.xbm b/wmglobe/src/cadre0.xbm new file mode 100644 index 0000000..50e15d8 --- /dev/null +++ b/wmglobe/src/cadre0.xbm @@ -0,0 +1,38 @@ +#define rond_width 64 +#define rond_height 64 +static char cadre0_bits[] = { + 0x00,0xe0,0xff,0xff,0xff,0xff,0x07,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x0f, + 0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, + 0x3f,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff, + 0xff,0xff,0xff,0xff,0x0f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0xff, + 0xff,0xff,0xff,0xff,0xff,0x3f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0x3f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xf0,0xff,0xff, + 0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff, + 0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0, + 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0x00,0xf8,0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0x1f, + 0x00,0x00,0xe0,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff, + 0x07,0x00}; diff --git a/wmglobe/src/cadre1.xbm b/wmglobe/src/cadre1.xbm new file mode 100644 index 0000000..1877818 --- /dev/null +++ b/wmglobe/src/cadre1.xbm @@ -0,0 +1,38 @@ +#define rond_width 64 +#define rond_height 64 +static char cadre1_bits[] = { + 0x00,0x00,0xc0,0xff,0xff,0x03,0x00,0x00,0x00,0x00,0xf8,0xff,0xff,0x1f,0x00, + 0x00,0x00,0x00,0xfe,0xff,0xff,0x7f,0x00,0x00,0x00,0x80,0xff,0xff,0xff,0xff, + 0x01,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x03,0x00,0x00,0xf0,0xff,0xff,0xff, + 0xff,0x0f,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x1f,0x00,0x00,0xfc,0xff,0xff, + 0xff,0xff,0x3f,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0xff,0xff, + 0xff,0xff,0xff,0xff,0x00,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0xc0,0xff, + 0xff,0xff,0xff,0xff,0xff,0x03,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0xe0, + 0xff,0xff,0xff,0xff,0xff,0xff,0x07,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff, + 0x1f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc,0xff,0xff,0xff,0xff,0xff, + 0xff,0x3f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfe,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfe, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfc,0xff,0xff,0xff,0xff,0xff,0xff, + 0x3f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xf8,0xff,0xff,0xff,0xff,0xff, + 0xff,0x1f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xe0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x07,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0x07,0xc0,0xff,0xff,0xff, + 0xff,0xff,0xff,0x03,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x00,0xff,0xff, + 0xff,0xff,0xff,0xff,0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0x7f,0x00,0x00,0xfc, + 0xff,0xff,0xff,0xff,0x3f,0x00,0x00,0xf8,0xff,0xff,0xff,0xff,0x1f,0x00,0x00, + 0xf0,0xff,0xff,0xff,0xff,0x0f,0x00,0x00,0xc0,0xff,0xff,0xff,0xff,0x03,0x00, + 0x00,0x80,0xff,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0xfe,0xff,0xff,0x7f,0x00, + 0x00,0x00,0x00,0xf8,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0xc0,0xff,0xff,0x03, + 0x00,0x00}; diff --git a/wmglobe/src/cadre2.xbm b/wmglobe/src/cadre2.xbm new file mode 100644 index 0000000..198de27 --- /dev/null +++ b/wmglobe/src/cadre2.xbm @@ -0,0 +1,38 @@ +#define cadre2_width 64 +#define cadre2_height 64 +static char cadre2_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff, + 0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff, + 0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0, + 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, + 0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff, + 0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff, + 0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff, + 0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0, + 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, + 0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff, + 0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff, + 0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff, + 0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0, + 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff, + 0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff, + 0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff, + 0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff, + 0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff, + 0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0, + 0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00}; diff --git a/wmglobe/src/defmap.xpm b/wmglobe/src/defmap.xpm new file mode 100644 index 0000000..b6029ec --- /dev/null +++ b/wmglobe/src/defmap.xpm @@ -0,0 +1,247 @@ +/* XPM */ +static char * defmap_xpm[] = { +"360 180 64 1", +" c None", +". c #B5FCF9", +"+ c #F5FDF8", +"@ c #7BF8F9", +"# c #84D8CD", +"$ c #82A7C9", +"% c #68BECA", +"& c #48BEDC", +"* c #48A4D2", +"= c #67A4C6", +"- c #6BD7DB", +"; c #4BF6FA", +"> c #438BC6", +", c #4CDCE6", +"' c #BBDAD0", +") c #82C0C6", +"! c #3053D6", +"~ c #3A3AFF", +"{ c #306FC2", +"] c #A1D8CC", +"^ c #648DC4", +"/ c #4570C8", +"( c #425CCD", +"_ c #A4C1CB", +": c #D7E0BC", +"< c #5A76C2", +"[ c #99ACC7", +"} c #81BF40", +"| c #8895D0", +"1 c #69A742", +"2 c #6D8F55", +"3 c #3A8E3D", +"4 c #BCD65E", +"5 c #5B7670", +"6 c #9FC04F", +"7 c #B9C155", +"8 c #9ED55E", +"9 c #DFC33E", +"0 c #9DA947", +"a c #82A745", +"b c #D7D955", +"c c #69BF3C", +"d c #69D947", +"e c #84D650", +"f c #B7AB41", +"g c #8E9243", +"h c #74ED42", +"i c #4EEC36", +"j c #445C91", +"k c #AAEE5E", +"l c #4EDC3C", +"m c #37D833", +"n c #3EC039", +"o c #46A63E", +"p c #34A439", +"q c #DCED65", +"r c #31734A", +"s c #45736A", +"t c #315594", +"u c #FAF755", +"v c #737A6D", +"w c #D58E2E", +"x c #F0DD45", +"y c #E2A935", +".+.+.+.++.++.+.+.+.+.+.+.+.+.+......+..+..+...+.........+.+.+.+....+..+...+.....................+..+..+..+...+...+...+..+..+..+...+...+...+.+..+.+.+.+.+.+.+.+..+.+.+.+.+..+.+.+..+..+..+...+..+..+..+..+..+..+..+..+..+..+..+..+.+..+..+.+..+..+..+.+.+..+.+.+..+..+..+..+..+.+..+..+..+..+..+..............+....+...........+......+...+...+..+...+.............+....+", +".+.++++++++++++++++++++.+.+.++++++++++.++.+++.+.+.+.+...+++++.++.+..+..++..+.+.+.+.+.+.+.++.+.+.+..+.+.+..+.+.++..++..+..+..+.+.+.+.+..+.+..++.+.+.+.+.+.+.+.+.+.+.+.++.+++.++.+.+.+.+.+.++.+.+.+.+.+.+.+.+.+.++.++.++.++.+.+.+.+.+.+.+.+.+.+.+..+.+.+.+.+.+.+.+.+.+.+.++.++.+.++.+.+.+.+.+....+.................................+......................................", +".+.+++++++++++.++++++++++++++++++++++++++++.++.+.++.++....+.+++++..+.+.+.+.+.......+...+...+..+.+.+.+.+.++.+.+..+...+.+.+.+.+.+.+..+.+.+.+.+.+.+.++.++.++++.++.+++++++++.++++++++.++.+.+.+.+.+.+.+.+.+.+.++.+.+.+.++.++.++.++.++.+.++.+.++.++.+++.+.+.++.+++.++.++.++.++.+.+.++.+.+.+.+.+..+.+..............................+...............+.......................@...", +".+.+.+...+.+++.+.+++++++++++++++++++++++++.+.++.+.+.+++.+..+..++++..+.+...+.+.+.+..+++.+++.++.+.+++.++.+..+.+.+.+.+.+...+..+..+.+.+..+...+.+.+.+..+.+.+..+.+.++.+.+.+.++.+.+.+.+++.+.+++.+.+.+.+.+.+.+.+.+.++.+.++.+.++.++.++.+.++.++.++.++.+.+.+.+++.++.+.++.++.+.++.++++.++.+++.++.++.++.+................................+.+...+................@.@..@.@.@.@.@.@.....", +"..+.....+..++++++++++++++++++++++++++++++++++++++++++.+.+.+.+.+.+.+...+.+...++.+.++.+++++++.++.+.+.+.+.+....@.@.@.@.............@.@..@..@...@@.@....@.@.@.@@......+.+.+++++++++.+.++.+.++.++.+.+.+.+.+.+.+.+.+.+.++++.++.++.++.++.++.++.++.+++.+++.+.++.+++.++.+++.+.++.+++.++..+..+.......................@.@.@...@................................@.@.@...............", +".+.+++.+.+.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+..++..+.+..+++++.++++++++.++.+..#$%&*&&*&**&=&--.@@@@@;;;;;;;;;;;&&*%*>>>**=********&,,,#-@@..@......+.+++.+++.+.++.+++.+.+++.+.+.+..+..+.+..++.++.++.++.++.+.+.+.++.+.+.+.+++.++.+.+.++.+.+++.++.+.+.++.......................@.@.@@@;;;;@.@@.@...........................@..............+......", +"..+.+.++.+++++++++++++++++++++++++++++++++++++++++++++++++++.+++.++.++++.++++++++++++++++++.+...')$%%>!~~!!~~~~~~~~~~~!!{>*>>**&&>*>*>{!!~~~!~~!!{{!!!{!!~~!>{{{!>&%&%-@@@@@@...++.++++.+.+..+.+......+....+......++..+..+..+.....+.+..+...+.+..+.+..+.+.++.+.+.+.+..+.+.++.+.+.+.@@@@..+.+...++.+..@@....@@@;@;@@@@.@..@....++.+.+.+................@....@.............", +"....+.+.+.+.+.+++++++++++++++++++++++++++++++++++++++++++++++.+++++++.+++.++.+.+.....+.+.]$^/(/(!{^$_]_].+.+...])$&=*!~~~~!~!!!!~~~!!>&*^>)$=$:.]..@@;;;,,{!~~~~~~~~~~!>****,;@@.+.+..+.']#_)%)=^^^^<=$%$^=>=-]..].'':.+.+...+..'.].':..:''.+:.:..+.+..+...+.............+.++.+......+............@@@.@....@@;@@.@@........+...+.+.+.+.+................................", +".+...+.+.+.++.+.+++++++++++++++++++++++++++++++++++++++++.+.+.+.+...+.+.+..+.']._)[)^>({(/)'''.+.:+..+++++++++:+.]%/!~~^$)'.+:#.]=]+:+..++++++++++++++..,,,&&&{~!!{~~~~~~~~~!{{>>%)%)$^!~~~~~~~~~~~~~~~~~~~~~~~!~~~~~!!~!!(!!((><<^/-@,,-&&*%=>>>>>^$)]])$-)=>%#%=^&-&&%)#@..@@@.......@......+.+.+++++.+++...+.++++++.........+++.+.+..+......+.+..", +".++..+.+.+.+.++++.+++++++++++++++++++++++++++++.+.+++++.++++++.+.+.....])^/{~~~~~~~~<%''=>*)_=_'_]+']]'+.+:++.]^!!)''.++++++++++++++++++++++++++++++++++++..@;;;;@=>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!!!~!!~~~~~~~~~~~~~~~~~~~~{>**=(~~!{%%&/=%~>^!~~!*&&{~~~~~~~~~~~~~~~~~~!/#..#{~~~~~~>#..+..++++++++++++++++++++..++++++++........+.+.+.......+++.+.+.+++++.+.+.+", +"++.++.++.++.+.+.++++++++++++++++++++..........+..+...+.+..+..'_]]-%$<(!~~~~!~~~~!~~~^)].:.:'%<*#$})'.+++++'$^!~~~!(:++++++++++++++++++++++++++++++++++++++++.@@,,>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=^=|>][))_)]]])<~~~~~~~~~~~~~~~~~~~~!~~~~~~~~!!!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!>>#.]##>~~~~~~/).++++++++++++++++++.+........+.+++++++++.+.+.+.+.++++.+++++++++.++++++++", +"+++++++++++++++++++++++++++++.++++++++..+.++.+++.+.]#$=^//!!~~!~~~~~~!~~~~~/>>>(~~{!!~<)'.'$1232#:.++++''>~!^|_':+++++++++++++++++++++++++++++++++++++++++++.@@!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!>)'__4::_=/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!(/>((>~~~~~~(]+++++++++++.+....@@@@;,,,,,@@.....+.++++.+.+.+++++++++++++++++++++++++", +"+++++++++++++++++++++++++++.+.+.++++.++..+..+....@@%>!~~~~~~~!!!~~~//{~~~~~~~~~~~~~!!~!~!>~!>=%#].:++'=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~!<(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{>>~!~~~!>_+.+.+.+.......@@@,-,,;,&&&&&-@@.....+...++.++++++++++++++++++++++++", +"+++++++++++++++++++++++++++++++++++++.++.+.+.......+.]>~~~{==>=>{(!~~~/!~~~!/~!!//~!^*<<^==^))'_]'#+.$!~~~~~~/=:.+++::++++++++++++++++++++++++++++++++++++++.-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!!{>%#>~~~~~~~~~~~~~~~~~~~~~~~~~!!(!!!(=]]-%*>><^/!(-...@@@@----]@..@...+..++++++++.+++.+.......++++++++++++++++++++++", +"+++++++.++++.++++++++++++++++++++++++++.+..+.+...+..]!~~~!!!!!~>-%%*//>%*=!~{({*)-!~/*!/_})5>/>$___$<~~~~~~~~~~!!~~~!~~(<[++++++++++++++++++++++++++++++++++..*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!*))#)=^/(~~~~~~~~~~~~~~~~~~~~!!(<^|$6_6_62]474].]#]]4__/**{!~~!~~!~~~{!{,;;@@;,#8]'].':++:+++++++++++.++++++++++++++++++++", +"+++++++++.+++++++++++++++++++++++++++++.+...+.+..])>!~~~!!!!~~~~!!^*>>!!!~~~~~~~!!~!/={~^^[^$[______(~~~~~~~~~~~~~~~~~~~~~/'+++++++++++++++++++++++++++++++++.%{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!%]#^(~~~~~~~~~~~~~~~~~~~~~~~~~^__474747794702a00a676776a$!~~~~~~~~~~~~~~~~>,;;;;;,,--]...+.:''++++++++++++++++++++++++++++++", +"++++.++.+++.++.+++++++++++++++.++.::+'.+....)^/(!~~~~~~(-###%-)>!~~~~~~~~{>!~~!(>>{~/)%=*!~{>={!(=^^$$^!~~~~~~~~~~~~~~~~~~~!]++++++++++++++++++++++++++++++]_=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*-->!~~~~~~~~~~~/!~~~~~~~~!<<^^$17497b777777777[76777$a2[aa<<<^<(~~~~/>/{!~~{&,;;;;;,&&--%==|<^$[''_____':+:++++++++++++++++++", +"[___.+....+.@@)><>^_'++.)//{!!!!!!~~!~!!!(!~~~~~~~~~~~!%##]#)>%-#)*={{>!)%%~~!>>%%=!{)^/!~/%c>/%)_]>=$:'<~~~~~~~~~~~~~~~~~~~{#+++++++++++++++++++++++++++:#$)>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!%-=!~~~~~~~~~~~!=_)^~!<~/(!(]4947977477979777777770a0a06607774bb476)$^)6)*=*!~~~!!{>*{>22a=/{!!!~~~~~~~~~~~>(><$''___[|[__|^|[|", +"!!~~/{{/{//<{!~~~~~~~!^<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!<)#)>!>#########-cd#{~~~!>$>!>c{~~~=c)1=}6e6%}%]+.]/&*'+++++++++++++++++++++++++']']/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!%--=!~~~~~~~~~~([47:2^)=a$]_6a[699797f774777979fffa0ga0aa6007f7f77b7b:40776a%(~!>{{{{(>=48_6))_'_=!!~~~~~~~~~~~~~~~~~~~~~~~~~~~!", +"/!~~~~~~~~~~~~~~~~!!/>=*^>>/!!(~~~~~~~~~~~~~~~~~~~~~~~~~~!~~~!>%c)c#hhhhihh%{(~~~~~>hii>~~!>*c))e)e-)c)7:+:']$^~~~~~~~~~~~~~~!*&#+++++++++++++++++++++++++$>)=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!/<=^^$$$<~~~~~~~~~~~~~~~~~~~~~~!^>>~~!~~~~~~!_4b44)j_7776774$a777777776}}}00a00aa222121a0a00f7ff6g0g0:+0g6:_g|7b[0_67777647766_4_[||$___>/~~~~~~~~~~~~~~~~~~~!", +"~~~~~~~~~~~~~~~~!%)##eekk]8#88]c-#%%=*!(!~~~!!!{{**=->!>!>>(~~!%--lllhlmlnllm*(~~{>>opmn3!~~~!{c%1/{/!/))]]8)4'#>~~~~~~~~~~~~).%{.++++++++++++++++++++++++._(<^~/==^^^^/!!", +"(!~~~~~~~~~~~!^=)8ddddde8e8k4kk8kkkkk8##-%==%n%dkhkh#h#hhhhhld*=c>>&*>*>npp>>!!~!>d&!{nmmp&*!~^)}%{~~~~/*})]876]{!~~~~~~~~~~~~!~!_+++++++++++++++++++++'[|/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(=^66a}}88648)8b'4:]']_|(~~~~~/(~~/>!/^=!^^^$^[49977[2a4947/$66a777777f7000a}a000}aa0aaa112ga1111aag00f0b497707:+q+:f:970ff007f00006000000677746a6))___])))==))6)a))[)", +"6)=r*p>rmiin&p>*oclcplmmimic{>#}))/~~~~)%((=8'8:+')>~~~~~~~~~~!>=+++++++++++++++++:|(!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sf6}ccc164666}6444_8'''':_$~~!]=(!^[]'77'4'b'4bbb7977777b7_ja7967f7779f707600}000aaa1aggag211a1}1a06440}6a00g2::+:+q::9ffgff00f70ag0g0000ff77777067667774_8_7744777447", +"6668){^=>~~~~~!/tr33pcdddddddldhhlihlhhhhhhhhehhhihihiiiild>&dihiiilhiinnhilmmlihldhliimimilc%*==>!~~~~~!~<)628]_':.#*!~~~~~~~(=)'+++++++++++++++_!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!|68acc}6446686}86688)}_]]'])!(()_$_'b9b4b7949b749776f77ff022[7977676f6776}aaa}0aa6aa}}aa2g2ag111111}aaa1111111120+++::f7u90gfffff00f0g0gg000ff7ff704:7776_74:77706067f0", +"^v)[8)8))^~~(%#8)-ccmnclnnlhhdlddlllihhhhhkkhhhhiiiiiiii,>{{pnliiilmmmiiiiiimmllllllmlmiimmd%>>{!~~~~~!~~{##}668=!/)_>~~~~~~~~!*''++++++++++:_=/~~~~~~~~~~~~/%^{^=))#^~~~~~~~~~~~~~~~~~~~~~~~~~~g7acc1}7b7|^2866666688$!~(!/$#']44:4bb4774477477770f67777767649766a}66a60606}}a}}a}a}ac}a111111111c1aa21a1121o111g:b+++7::gf00ffffw0fggff0g0f7ff60007:47:+b9777600770[6_", +"!~~~!^)^~~~~~/^=1=3dcnlllndnmcdkkchidihhhhhkkkhiiiiiiiiimnmlililiiiimmmnmmnmmmmmnlmlmmmmimi%>()#%>!~~~=-^*$]%}]8]=<~!~~~~~~~~~~~{)+++++++++]~~~~~~~~~~~~~~~~~/e]6.++.=!~~~~~~~~~~~~~~~~~~~~~~~t|71cc164942~!=666676776}//)$2)4b4b447468666477666600606f7666766666}}c}}66}06a}}}1}1}ccc11a11112111o11a0a1111112o11aa7::++++:b+4776000ff0gf0f000gag0_:v:++::::970776706a5j", +"~~~~~~!~~!~~~~~~~!rnnnldedo]k+.:+.keddhdlhehkhhiiihiiiiiiiiiiimiiiiimmlmmmmnmmpnnnmlmlmmm*!!~{=%({>!~~!~~~~{$]]})6)/~~~~~~~~~~~~(#+++++++++<~~~~~~~~~~~~~~~~~!/*=]^<~~~~~~~~~~~~~~~~~~~~~~~~jv[0acdc}9b[v!56746676774868864q4747b948}cd}c}e}}}8}}aa}6af7}}676}6}}}}}c1}}}}ac}}cc11}1cc}1111121211112a0aag112o11o1212a0777:+:+++++b7fggggfggwggg70:::::9:f77ffff677777[a~", +"~~~~~~~~~~!~~~!p%ddcncdeddo1+:e6}4':+qeccdeddkhihiiiiiiiiiiiimiilllmmnlmmmmnnn{pmmnmmli*{!~~~~~~((~~!~//!!(~~/=)%>/!~~~~~~~~~~~~~*:++++++]!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!v06}}1ccc677j!~_76}11aa6646688bbb744b748ee}dcc}}ccc}111a}}}6676}}666}}}c}c}}}}a}}1}}}}}1}1ac11a22221212112222a12111111o1o132522v2fb:+++++:47000000070++++7fgg5v20ggg7+++:_'_]<", +"~~~~~~~~~~~~~~*cnncpnnncdhe+eoddk'}]::+:88k}kdhdiiiimiiiiiiiiiii&t{nmmmmmmmnnnnmmmmmml{~~~~~~~~~~~~~/~#8_4])!~~~!!~~~~~~~~~~~~~~~~<:+++++)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~0fa1ccc1}a74v~~~a701c1}a7f686}14bb486466e}dcccdcdcdcdc11a6}}}66}}}}}c}ccc}}}}c}a}}ac1c111c1aaaaaaag1221222522g11aa211111o111o231226:x::+++++++::7+++:++_vj5g_2s0:++:++:051nnldnlnce]%odd-><]8].'++'_:8dldhiimimmiiiiiiiimp&lmimmmmmmnmnnmnmmnm*~~~~~~~~~~~~~~~~=664648)/~~~~~~~~~~~~~~~~~~~~!||_+:!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!071oc1cc}}67[(~![886_}$64as288}4848}eee}ddceccdcccccc}11a}c}}67}1cccccccc1c1}c}}a}}}}cccc1}c}aaagga2g222222a11111a2121o1111112121a4q:ff+:b::+++++++++:v!~~!5t^'+_72g_[5t~~~~~~~", +"~~~~~~~~~~~~~(~!({clcponnc*t*)s>s3nd#{!~~~~~~~~~~~~~t$)}8kcdlclmmmiiiiiiiiiiiimmmimimmmnmmmmmnmmn*~~~~~~~~~~~~~~()4844448c5&/~~~~~~~~~~~~~~~s#11.8]8]dcnhmiiiiiilhiiimiimimmmmnnmmnnmmii>!~~~~~~~~~~~~~!6886484ee#8848=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{1c3/~~~~~~~~!!!!/(7676$!|!~/as6471}e}}}}ee}888}ec}cecdcddcc}cccc11}66d}c}}}}c}cccc1}1}a}}}}}aa}11cc}1a1aaag0g121212a1aa0660:7++:+7440::q4+::+a6++$!~~~~~~~~~~~~~~~~52:+72~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~^%^!~!!~~~~~~~~~~~~~~~~~{=odnce''#1cdliiiiikhhimiimniiimmnmmnnnnpmmnhd&>~~~~~~~~~~~^}e86}48166k6k8!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!=cc3~~~~~~~~~~=c=!26}8|~!~!_776766}}cccceecd}ec}}e}e}dd}}}d}dcdcc}6688e}}66}6}a6}ac1cc}a0}}}aa11111a1aaaaga222a2111}1a07:7++q++4q:+q:7'::+:70++_/~~~~~~~~~~~~~~~~!22:::2v!~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~(/^/~~~~~~~~~~~~~~~~~~~~~~~~~2noldk}'kdnomiimiililliiimnmmmmnmnmmnpnmnnlldd%*(!!~~~~~/84}}}a676}86a88=(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!scc1!~~~~~~~~~^c12a_^!~~~~t677666}c}cd}ccdeced}d}}eedce}e}6}e}cc}}}664777777977f606a}}766f}6aag1gaaaaa0gaga222g2aa6a6ga094:b:+b7:++:+++++:x::b|t~~~~~~~~~~~~~~~~~/2::072!~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~!t!onlnooddcdndiilllmmmimmmmmnnnmmmnpnnnpnmlnddn%c-=~~!=88a}ccnn188cdek88})>!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{1c>/2}a!~~~~~~~~/1132s!t>2^/60660}}}c}}ceec}eeed}ee}}8}e}8444488}}}66679xxx9xxx9497976779b99977aa1a}66b07g622g221g2a'2670074f++::++x:4f77fb:4002s/!~~~~~~~~~~~~~~~~(0:7gv<~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=~{ndlnocdoc8keddlnniiimimmmmmpn3p{3mmmmmmnncoceeed~~!eenoonnmnnndlnnldeco}$/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^}4)~~{}86!~~~~!jsocc1a81611a}6}6666}a}6e6e}ece}dc}ce}}88446bxxb7478fb9bb9xxxuxuux9b9bb9bb94999x90aa0a467+qu0g002221083070004b:++:x:b4:+:0aa0a00aa121a5(^!~~~~~~~~~~~!_:62!~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!~tcdmllnnncek+kddldhiiimmmmmmnpp>!mmmmnmmn3oodeed3!~cnnmnnnnnmmlmlmlllce66)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>161!(c}}61(~~!3ccccc}a6}1}}}ac}}e}8}}66686e}}}eeee}e}88}44xqxxb994769xxxxuuxuuuuuuxxx9bbbbbqxuq977f704:+b74q:bf00a112_4404:+q::::9++::9qf0060a0}1a0a2128(~~~~~~~~~~~~$4<~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tdekddlllnd]q.dlllilimmmmmmnnpnnpmmmmmnppppnopll{{nnnnppnnnnmmmllndde}6$=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!>>t~~>1cee}!~jocc1ccc11}1}}666}c}cc}cc}}8}6}888}e846848484bxxbxxxb97b9xxxuuuuuuuuuuuuuxxuxxuuuuuxbx9774:7:b4:b'b47aa6407:+:+:xb9fff7+ub77fffyff7610a66a50/~~~~~~~~~~~~/5!~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!od1dklmlmnnck'hdlmlimmmmmmmmmnmmmmnnnnppnmmmpnpmnnppnppnnnnmlndee)e)^!/%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/*/5/j{1c}c}ccc}c1111}aa}}c}c}}11}66}664bb4e}844bbb74xqxquxxxb9xxxuuuuuuuuxuuuuuuuuuuuuuuuuuxbbx:7b+::77f0:::470f79q+:x:9yfyf79+:9yfwyy9yf:4600:_v!62~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!1ennlmmmmnoc:enllilmmmmmmmnmmmmmpnnmnn3nmnmmnnnnnpnnpnnpnmncr!!{!!~~~[a!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{j*1ccccccc}ccc111}1111}}1c11}}66}}664446}8464bbbxqxuuxxxxx9xuuuuuuxuuuuuuuuxxxuuuuuuuuxxuq+:xf4xb9::b777ff077:+++x9x9xfff:++x9f9fyfyf0ff0a6:as~a=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{}pomlllmno%kdnmlilmimmnmnnnmmmnnnmmn{{pmmnnpnnmnnnpnnpmmpon}/~~~~~^6}[=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(^>a6}ccccccc1}ac}111}}1}111}}}0}6646}6}64bb4bx49bxuuxuxuuuuuuuuuuuxuuuxuuuuuuuuuuuuuuuxxbbx:x+q+bf7:+9+:bb77gb:q++xx9x999y9x::9yyy9yy9f0aaaa0q:2!!a!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2dcdldmicdooppocllliimmnnmnmnmnmmm3!!~~{mmnnnnnnpppnpnnmmm}c!~~~~!<^^1=<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t>168cccccc1ncc}1caaa}}6}}ca1c}a}679bb97b77b99bxbqxuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuqxxxb:u+ubb9bbf:qbbf7bb99xuxxxx99xxx9q9yy9999fgf2aag047g(~!^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~thhhhdlmnncccoponniiiiimmmmmnmmnmnp*p>{{pnnnnnpppppnpponmlee{~~~!~~~~~~/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!a4}ccccc1c}:8a}c1aa}}}6}e}}}}67b7g77b6vr7qxxxxuuuxx4|s5buuuuuuuuuuuuuuuuuuuuquuuuuuxuubxuxbx9xu++47fb:x:x9xxxxxuxxxxxx9xxb9y99999wgga2gg007as~~t=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!8keedncd#.:]'eopnnnmiiimmnmmmmmmmmmnn>>&!{{3nnnpnppppoolndco*>{!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j}ecccncc8:+}a2a6}}0}6}76}846860t~s645s5bxxxxxxuub5!~<0uuuuuuk#quuuuuuuuuuuubuuuuuuquxuuuuuuuuxxxu+:bbx9x9xxxxxxxxxx9xx99:9999799fgggg1ggg0^~~~!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tkhkhhln}k'+48]:ok3pnmmnmmnmmmmmmmmmm>!di&~{3nnmmnmppooon>t>c*/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s}cnccncc1:1165t566006a676}4b70j~~~^ajt^4bxxxuxuqg~~^q+uuuuuk,dquuuxuuuuuuuuuuuuuqxxxuuuuuuuxuuuxxxuu999x9xxxuxuuxxxxx9x:ff979fyyf22g21g0gs~~~~s$j~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{hdhkhhickkk'8:ee'}onnpnmmmmmmmmmmmmm{{lll>olmp33nnnpnot~~~>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/=pppppp3ppt~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!64611111::cct~~!~!!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(llhhkkqh8qu7:+]o'q+oolilihiiiimmmnnnnnnpnpnnp3333p3t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~a7f9799775!~~~~~~|0~~~t|b7|t[b9972vff0bbxxxxqxb979xxxuxuxx:!~!'buuuuuuuuuuuuuxbxxq:+++xuxuuuuuuuxuuxxxuuuuuuxuuuuuxxxxxxxx9x7f0ga1s11aggga/~~~~~~~~~!2^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tcilehkkkquu4:86]8.:onnhdhhhhiimmnmmmmmnpnnnnp33rp3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(bb979qxx7~~!!~~~~0g~~~~~v7t!j7b75~jf9xxuuxuuxxxxxx9xuuquqq7~~~_uuuuuuuuuuxuxxuqu+++uquuuuuuuuuuuuuuxuxxuuuuuuuuuuuxxx9999x9900a1s!52s5aagt~~~~~~~~~~(6[!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>diekkkqkqq4:1o1]q'1oldiiihhkilmmmmnmmpnnnnnpr33pt~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(bxbbxxuu7~~~~~~~~!!~~~!!jf~~~5790/!g9xxuuuxxxxx9xuuuuuxuxqv~~~tuuxuuuuuuxuuxuux:u:+:uuuuuuuuuuuuuxxxuuxuxuxxxxxuuuuxuxxxyffffa2j~~!~~!a66(~~~~~~~~~~sa<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!3hd'kkqqqqqkoc.+:.enldihddhhhhlnmmnnmnnnn333rp3!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~7bbxuuu_(~~~~~~~~~j~~<':5!~~~!|bg(!5y9xxxxuxx9xxxuuuuuqquu7<~~tuuxuuxuuxuuuuxbx::++u:uuuuuuuuxxbxqxxxuxuxx99999xuxxuxxxyffw00aa}j>s!~~/2g_!~~~~~~~!sa1!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!ohcqquuqu4kcn}e.:8nlhhhiidhhkmmnnnmmnmnp3rrrpp!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!g70v5!~tvg0g07f9x7!~!11}=/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>c8quuxuxq8k]38]ppcehkhlhllmmmmmmnnnnprrronp{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~vuxuuuuuuuuuuuuuu9j~~~~~~~~~~~~!(~~~~~~!=!jquuuuuuuuuqxuuuuuuuuuuxxxxxxuquqx9b09+++:u:uxxxx+x+qxxb+q:xbff9f0ff00gfggf0a0}}}}cc2!~~~~~^5(~!<}12o={!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tj6uuuuux8]eoc8cndqqbkddhllnllnmnlncp3r33{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tgxxxuuuuuuuuuuuuuu45~~~~~~~~~~~~~~~~~~~~~~!auuuuuuuuuuuxuuuuuxuuxuxxxuxxquxqqq7bbb:++++xqxxxxu+xxx:x::++b7fff6fffgffff000}cce}}a^~~~~~!~~(2o1^s/!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~jb4uuuuqcer311ocbkqqeldddllmlmmnonnp33!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!9xu9uuuuuuuuuuuuuuuuu97gj~~~~^:_5!~~~~~~~~~(kxuuuuuuuuuuuuxuuuuquuxx9xxuxxxxbb9qqxb7:++++:x9bxxx:xxx++:+++:b000f0wg0f0f00}ac}c}e}_!~~~~~~~($2(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~a46buuu8co33on}bqqkkddeehdilnnnnmnno!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~0uxxuuuuuuuuuuuuuuuuuuuuu7j!~juuuu:[|/!!/(!jauuuuuuuuuuuuuuuxuuuuquxxxbxuuuxb999bu4747q++++:+b9xxb9:++:++:++:b77gfgfggff}}6c}}}cc}6$~~~~~~~~=/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!65tuuuq8eonnd84bxk4eekqhlinn33nnmm3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~fbxxxuuuuuuuuuuuuuuuuuuuuuu:|vuuuuuuuu::48quuuuuuuuuuuuuuuuquxuuuxqxxxxuuuuuuxxqxb46797y7:+:+:::b::u+u:q+++++++:fggg0ag0a}}}a8}}ce6=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<$tguqu4}8}oc87xb8ekk}21o*t~~!t{rno~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~jbxuxuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu0jaquxuuuuqxxxxuxuuuuuxbbbxb9bbf7b+++:u++:bf_:+++++:+bgggfgg0a1a1c66}8}c})!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s%j0uuq8qb}o148behc{~~~~~~~~~~~~3n!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/~(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!/!5:uxuuuuuuuuuuuuuuuuuuuuuuuuuuubuuuuuuuuuuuuuuuq^0qxuuuuuuuuuuu5~j6qxquququxxxuxbqxquuuuux79bbxbb70f7+++:++f77g4bag2ggg0g0a111}}}}6e})=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<%/~aq06b44}ecndo~~~~~~~~~~~~~~tpn~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(:uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu9uuuuuuuuuuuuuuuq{!4buuuuuuuuuuuu5~~<[a54bbqbquqxxxxuuuuxxx7677bqbb777f7fgf0ggfg00ggaggggggaa1aae}e}cc&~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/]~j6807bqec3od>~~~~~~~~~~~~~~~{{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~7uuuuuuuuuuuuuuuuuuuuuqxuuuuuuuuuuuuuuuuuuuuuuuuq$~<447xuuuuuuuuu4_~~t$2<)74q44477xxxuxxxx977779bbxb9bb766aggggg0000gggggggaaa1a}cccdc/~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!_>~t}4b64edppk{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~juuuuuuuuuuuuuuuuuuuuuuuquuuuuuuuuuuuuuuuuuuuuuuuuq/!_77xuuuuuuuuuu7jj[+a~!~~t!!~!t4buuxx97f9997xxqbbxbb460a0ggga000ggggagaagggaaa}ccc>~{^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^/~!6661o1npc{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~juuuuuuuuuuuuuuuuuuuuuuxuuuuuuuuuuuuuuuuuuuuuuuuuuuu0~t674xuuuuuuuuuuuuuuk_^!~~~~~~~j6quxx9979997xxxbxbb4466}00gaga00gggg2g0aaa2g1ccc%(~!2^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tck}p33nn!~~~~~~~~~~~~~!t{{!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuxuuuuuuuuuuuuuuuq^~j74uuuuuuuuuuuuuuuuqb|~~~~~~~~!0997b79b97fbbxbxxb468#caa000ag00aa1gg0a}aa}12^/!~~~|t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s}cc333nr~~~~~~~~t!~~~~~!!ttt~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~juuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuxxxuuuuuuuuuuuuuuuxb!t:buquuuuuuuuuuuuuuuu2~~~~~~~~~577g7799979xxbbbbba^>!(}a0a0aa0ga1122a25115/~~~~~~~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sonpppppp~~~~~~!rpp~~~~~~~~~{rt~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!7uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu99uuuuuuuuuuuuuuuquq5~[bbuuuuuuuuuuuuuuuu_!~~~~~~~~~~5js79477x9bxbxbb'!~~~~2a0}a01aa}}1a25!~jr!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!ndnp33ppt~~~~~t33{~~~~~~~~~~!!~~!t!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuxuuuuuuuuuuuuuuuuub2~!2quuuuuuuuuuuuuuu4~~~~~~~~~~~~~~s79967x99xbbb$(~~~~~!566ggga0}}cc1!~!1^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~3nn33p3r!~~~tr33!~~~~~~~~~~~~~~{p3!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~vuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu4t~!7quuuuuuuuuuuuu:v~~~~~~~~~~~~~~t797f99x9bbbg~~~~~~~~t006ag00}1}11~~(a{~~~~~~~~~!(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!r3pcp3r33rrr33~~~~~~~~~~{~~~~~t~~~~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~5uuuuuuuuuuuuuuuuuuuuuuuxxuuuuuuuuuuuuuuuuuuuuuuuuuuuux:~~j:uuuuuuuuuuuu0(~~~~~~~~~~~~~~~!f9977bbxx4v~~~~~~~~~~v076aaa0a}11s!~~~~~~~~~~~~^1(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{s3pp3rr3rpp~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu5~!$uuuuuuuuu:0^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!3pp{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[9xx99yyy9xxxxuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuxxxx9xxb4a$j~~~~~~~~~~~~~~~~~~~~~~~~~~~~j9xx99<~~~~~~~~~~~!!~~~~5}jv600}a}at~~~~~~~~~~(5t5(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!ppt~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j06000fgfy999x9xxuuuuuuuuuuuuuuuuxxxx9xxxuuuuuxxuxxx9xb9xbb4v~~!tj|_(~~~~~~~~~~~~~~~~~~~~~~~gbxx9~~~~~~~~~~~~~~~~~~sa!~j6666aa!~~~~~~~~~!~t2ts/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{n{~~~~~~~~~t>3tj~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!acc}0aa6f999999xuxxuuuuuuuuuuuxx99bb9xxxxxx999xxx9xx9bbxbqqg07uu++<~~~~~~~~~~~~~~~~~~~~~~~t4xx7~~~~~~~~~~~~~~~~~~5^~~~2a0}2!~~~~~~~~~~{~!23sj~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~r3!~~~~~~!3ppop33s{~~s!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!o}}}}}}}}}}}a7bb46xxb76bxxxxux9977799yyyy99999xxxxb9xxxxuuuuuuuu:~~~~~~~~~~~~~~~~~~~~~~~~~fxbs^~~~~~~~~~~~~~~~~!22~~~!s)=~~~~~~~~~~~/~~~<>ss~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!3pr!tt~{ppp33r3oooopn*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{c8}}}ccccoc}}06}a67a1a667b4977}}6}a7f99yyy9999x9x9bxxxxxxuuuuuu|~~~~~~~~~~~~~~~~~~~~~~~~~54js45~~~~~~~~~~~~~~~~a4j~~~(s~~~~~~~~~~~!!~~~tss1j~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{{~tpr33rr3r3nooooonn=!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!)88}cccncc}}}1a}a}}}cc1}}6}aca11cc166f6f99999xbb9x9xxxxuxxxxuu:!~~~~~~~~~~~~~~~~~~~~~~~~~~!~57[~~~~~~~~~~~~~~~~t6g!~~~~~~~~~~~~~~~~~~~!s>a25~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t3rrrrr3ooon313ooabj~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!>686ee}e}446}}}a0}c1cc1}ccccc1ccccc}}}66f7999xxbxxxxxxuuxxuuuv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t4a~~~~~~~~~~~!~!~~~j6gt~~~~~~~~~~~~~s5~~~~!!15!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t3rrsr33oono3o3o31a)(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t}846888846>t~!t1}}cce}cdnclcnccclc}c}67999b9xxxxxxxxxuuxuu:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~~~~~~~~~~~~~~5jt~!a70!~~~~~~~~~~~s}6$!~~~~t!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t3rrr3333po333ooo3o1)a|0|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!^)^(!!(j!~~~~~<$12ccccccccnccncndcc6694x9x9xxqxxxxuxuxuuuj~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~546j!57bg~~~~~~~~~!2a67g~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!rr3333o3333o333o3331264q7/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!sc}ccnccncncccc}67799b9x99xuxxuxxx99xuv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!540sj67g~~~~!~~~!s1aa2!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t2r333333pooo3333o3poo1}a}a~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tac}cccc1nccc}}8679bbb9x9xxqxxuq9x9xqv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t568s247!~~~~~~^a11a6a~~~~~~~~~~(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(31r3oppp33popp3o3o3pooooooo!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~tc}}1ccoccc}67677799b99b9bxxxqqxx99f(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j387620/~~~!0a}111}07<~~!~~(!~^s~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>3r333o333333opp33oo3opoopno{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/}}}}}}acc67b77677994b9xbbbbxxqqb9[~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!t66b61j~~~(bb4a11a60j!5>22^~~^v~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%srrro3p3333333333p33p3opooooo!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2}}c686}}6877777y99949b5sbbbxxxx9a~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!j}4b}s~~~!9bb6aaa70~sttsj~~~^t!/j|j~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t1rr33333333333oo33p33o3o333pnno{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2686646}666449979999b94j^xbxx9xb0!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(j26442s~~~vxx6a077t~0f7a5(t~/~!/076/((t!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$1rr3333p3333333333o3333pp3onnnonost~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j476666676979999999999464b9bxbx0!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!r76b67^!~t7qf6f9v~t797t~jj!~tjjt215~311>j!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^13r3p33333r333p33r3333o3oooo3nooopoo/!~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~587476674999x9xx9x9b99bb9b9999t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!569b4j!!~jvgg7bj~!6v72~~~$j$22!<6}2ooco112(~~~~~~~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~to33333333p333r3o333o3oo3o33oooopo3cd647x9<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~5646776f9b9999x9x999xxxbbxxx0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~v446t~~~~~~~jj~~~2220t~~t~~~!~~t!=1coooooo^(~~~~~((~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!'13p333333pp33333o3p3p33p33pooonooon1}4f9x9j~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~a74477799999x9x9b6b9xxx9bxbj~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j66t~~~~~~~~~~~~//t^t~~~~~~~~~!!~!{cooo3oo1!!({!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<64477b999999999xf49xxbb9bb<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ts60vtjj!!~~~~~~!~~~~~~~~~~~~!^~~~>ooo3ooo}<~!!~~~~!~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$}33333r3333p333333333p3p3ooopopoooccc007qxb66!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!6444799999999x9xb7b9xxbbbq2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~5[777462t~~~~~!~~!~!(~~~!/~~~~~~>11ooo>3}s~~~~~~~~!~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>1r13333333pppoop3333pp3popooopooc}e60f747744/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~g4444b9x999xx9bbb7bb9bb9bqv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!jgg$2<^^^j^^/ss52!~~~!~~~~~!{sa6a/~t51(~~~~~~~~!~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=31333333pop3p3p3333oop3popopooo160006}cce77j~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~644b49x9999xb946444q9bb9bx0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~!!t2st~sa2t~~~~~~~~~~~~~!//!~~!>1/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{or33333333p33op3333op33poonoooc146a6}ccdc40!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/[333333p3r333333p3oo33ooocooca7}}cc}0}})~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$qb4qbqqxx9xxxq44q4qkebbbbq|~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~s2a6a%^~~~~(c!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)a3r3333333p333p33ooo3onnoco167a0}0}}66/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^7a^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]c28r2rr33o}11211111oponc169999b7}e88!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!qubqqqquxuuuxb7bbqbk4kk4kkk'^~~~~!<84:^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^'':181o}}4bxuuq4}1oooc84qq8686668}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j:uuuuuuuuuuuuuuu|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~gyywwwyyyy9ywyywy99y99xuuuuxx99yffgfw005~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!:9q46}}buxx4}48kqxecnc{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~5uuuuuuuuuuuuuu[~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t9yywywy9yyywywyyy9y99xuuuuuuu9yywff067<~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(~5f99xxx9994!~~~~~~~~~~~~~~~~~~~~~~~/~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~g6abxxxuxuxxuuuq<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~![7y9y99770~~~~~~~~~~~~~~~~~~~~~~~~jvt~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~jf84quxuxxuxuxuuq<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!/2[5a_5!~~~~~~~~~~~~~~~~~~~~~~~~~j2v2!~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~50:4uuuuuuuxuuxbv~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!v3vt~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j94qxuxuuxubv(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!~!(~~~~~~~~~~~~~~~~~~~~~~~~~t5j~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~v:0xuuuuuxu:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!a=}(~~~~~~~~~~~~~~~~~~~~~~!53(s~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~f:4uquxxu5v<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=}1!~~~~~~~~~~~~~~~~~~~~~~[a^~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2[9xuuuuu2<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!=(~~~~~~~~~~~~~~~~~~~~~([15~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t56bxuqxq_/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~![g1j!~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!^6buuuu4$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!a5a=~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~j54bxqx:^!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/2/!~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~![_4bxuq6~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~5q84xxu4*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t):8bbuq4>!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(6:_xbxu|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!$:8xxq[!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2:49q:j~~~~~~~~!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~t[:xq9<~~~~~~~~(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~5:6fb:!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<$0bx7^!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(|[|(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/^((~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(/<'_[)!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!]:${~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/~(~~~~~~~~~!//!~~~~~~~~~~~~~~~~~~|_~~~~~~~!(!(!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~![:']&/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|_+++:|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!~|<~~~((<|(!<:::'_[|<(([::.'#=!~(/!<<||[(~(|[[['+[[<<~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(!~~~~~!|:+++++++++++++++++++++++++++!~~~!~~~[:++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++:_|<(<~~~~~~~~~~~~~~~~~~~~~~~~~~", +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(_'(<_+++.,*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~([++[<^~|+++++++++++++++++++++++++++++:!!~~(<[:++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++:'''[ c #26393C", +", c #29120C", +"' c #464543", +") c #6E6E70", +"! c #1A353C", +"~ c #574A49", +"{ c #765A34", +"] c #764A24", +"^ c #562E1C", +"/ c #0C0E14", +"( c #6E3917", +"_ c #302E28", +": c #291C17", +"< c #423A1B", +"[ c #373836", +"} c #161D14", +"| c #1A2427", +"1 c #5A3A24", +"2 c #65625C", +"3 c #5A524C", +"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", +"!!!!>>>>>>>>>>>>>>!>>>>!!!!!!!>!!!!>!>!!!!!!!!!!!!!!!!!!!>>>>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>!!!!!!!!>!>!>!>!>!>!>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!!", +"!!!>>>>>>>>>>!!!>>>>>>>>>>>>>>[+>>>+>>>>>>!!>>!!!!!!!!!!!!!!!>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>!>!!>!>!!!!>!>!!!!!!!!!>!!!!!>!!!>!!>!!!>!!!!!!!!!!!!!!!!!!!!!!!!!!>!>!>!>!>!!>!!>!!!!>!!>!>!!!!!!>!!!>!!>!>!>!>!!!!>!!>!>!>!>!>!!>!!!!!!!!!!!!!!!!#!#!#!##!##!#!##!##!###!##!!#!#!!#!!#!!#!!!!!#!!#!###!########!##!#!##!", +"!!!!!!!!!!!!>!>!!>>+>+[[>+[>+>>[>+>[>+>[+>!!!!!!!!!!>!!!!!!!!!!>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>!>!!!!!!>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>!!!!!!>>!>>!>!>!>!>!>!>!>!!!!!!!!!!!!!!!!!!>!!>!>!!!>!!>!!!!!!!!!!!>!!!!!>!>!!>!!!!>!>>!!!!!>!!!!!!>!!!>!>!!!!>!!>!!!!>!!!!!>!!>!!!!!!!#!!#!!!!#!!!!!!!!!!!#!#!!!!!!!!!!!#!!!#!#!!##!#!!#!#!!#!#!!!!!!#!#!#!#!!!!", +"#!!!!!#!!!!!>!>!>[>[[>+>+>[[[+++[[>>>>>>!>>>>+>>+>>>!!!!!!!!!>!!!!!!!!!!!!!!!!!!!!!!>!>!>!>!!!!>!!>!!>!!!!!#!!#!###!#!#!!!!!!!!!!!!!!#!#!!!!#!##!!!!!#!!#!!#!!!!!!!!!!!>!!!>!!!>!>!!>!>!>!!>!!!>!!!!!!!!!!>!!!!!>!>!>!>!>!>!>!>!!!!>!!!>>!!!!!!>!>!!>!>!>!>!>!!!>!!>!!>!!!>!!>!!!!!!!!!!!!!!#!!#!!#!#!!#!##!#####!##!####!##!!!!!#!!#!!#!!!!!#!!#!#!!!####!#!!!!!!!!#!!!", +"!!!!!!>!!!!>[[>>[>++++++[>>>>+'[+>+>>>>>>!>>>+>+>++++++>>!>>!>>>>>!!!!!!!!!!!!!!!!!>!>>!>>>>!>!!!!!!!!####}}}/}}}}}}}###################}}/}}////}/=///==/=/#}#}####!#!!!!!!>!!!!!>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>!!!!!>!!>!!!!>!>!>!!!!!>!>!!!!!!!>!>!!!!>!!!!>!!!!!!!!!#!#!!!!!#!!#!!#!!#!##!#!#######!!!#!!!!#!!##!#!!#>!!!!!#!#!!#!!#!!#!!!!!#!!#!#!#!!!#!!", +"!!!!!!!!!>!!>>>[>++++[';++>+>++++>+'';+[[>>>![>[>+[+>>+>+>!>!!>!!>!>!!!!!!>!!!>>!!>>>>!>!>>!>!!!|#}#==..../...../........//=//=}//}/=//............././/........./=}}}}######!!!!!!!>!!!#!_!#!!!!!!!#!#|!#!!!#!#!!!!!!!!!!!!!!!#!!!#!!!!#!!!!!!!!!!!!!>!!!!!!!!!!!!!!>!!!!!!!!!#!!######!!!!#!!!!!!!#!!!!!#!########!###!##!!!!!!!!!#!#!!!!#!!#!!!!#!##!!#!#!#!#!#!#!##!", +"#|#>#!!!!!!!!!!!>>>+[++>+[>>>>>[>>[[++>+>'++'>+>>>+>+[!>!>>!!>!>!!>!>>>>!!!>>!!!!!!!!!>!!!}=/.//.///}#=}|#|!#|##/}///................/}=}/|}#}_!#||###/}}}//............//==}=}#|#_!#>#_#}}}}}=//////}}/}/./=##||#||||#|!#!##|#!##||##|!#|#!#!|!#!!!!!!!!!!!!!#!!!!!#!!!!!!!!>!|#|#!!!#!####!!!!!!!#!!##!!######!##!#!!!#>!!!!>#!!!!!!!!!#!!!!!#!!!#!!#!#!!!!!!!!!#!!!!!", +">!!!!!!!!!!!!!>!!!!>!>>>>+>>>>>>>>>>>>>+>>>>[>>>>>>>>>>>>!!!!!!>>!!!!!!!!!>!!!#!##}}=/../=|}|||_||_||>##>>__>_|||}=//..=}|#!>>|#|}|>>|!|!!>[[>>+>+!!!>##}#/}}//.../........./..//}}}==/....................................//...............///..../////}}#|}===///=///=/}||==}}=}/=}}/}}}/}####!###!!!!!#!##!##!!!!!!!>!!!!!!!!!!!!!>!!!!!!#!#!#!!!!!!!!!!!!!!!!!!!!!!!", +"!!!!!#!_#!!!!!!!!>!>>>>[>![>>>>>>>>>_>!!!>!>!>!!!!!!!>>!>>>>!>!!!!!!!!###}/........./|>>|//=}}}|}|#|=:|&_|>#>||=./:|!|>>[>>>>[>+>>>[>>[+[+[>+[+[+[[[>[+>>!!#######//..............................................................//==|..../}|#/||./=/../////.................../}!#|......./##!!!!>>>>>>>>>>!+!+>>>>>!!>>>>>!!>##!!!!!!!!!!!!!!!#!!!>>!!!!!!!!!!!!!#!#!", +"!!#!>>!>!>!!!>!>!>>>>>>+>>>>+>>>>>>!!!!#!!!!!!!!!!!!!!!!!!>!|##|#}}}................=|_[>++_}==}/}=}|_>!>_|==...../_[+>+>'[++[>+[+>++>[+[>++>>>+>+++[>+++++!#}#/=/.............................=}=}/_::|__|>!&/...................../...........................................//}|}==/.......##!!+>++>+>+>+>+>>>!>!!#!#!!!>>!>!>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!>!>>>>_", +">[>>!!>>>>_>>!>>>!!>>>>>>>!>!>>!>>!>!!!>!!!!!>!>!!!##}}///.........../.....}=///..//../:>>>|}=/==}|!!_||}=.//=:|!>!>>+>+++>+>+++++++>++[>+[+'[+++[+++++++[+>!##.............................../=|_&|||_:=/...........................................................................//.//.......#!>>>>>>!+>!!!!!!#######=#=###!##!!!>>>>!!!!!!!>>>>>+>>>>+>+>+>+>>+>+>>", +">>>>[>!>>!>!!>!>>>>>>>>>>>_!!!!!!>!!>!!!!!!!!!!!!##=/........../...///............../.../=.//}/=}=|>_#=/....}||__>[+[[[>[+>'>[>>[>+>+[+++[+[++[[++[++[+[+>>#!}/.....................................=//....................................................................................//.....//}!!!!!!!!#!#!!!###}|}|#/}}}==#}##!!!!!!!!!!!!>+>>+++>[>>>[+![>>[>>>>", +">>>!!!>!>>>>>>>!>!>!>!>>>>!!>>>>>>>>>!>!!!!!!#!!!!!!!!..../=}=}=//..../...../..///../}=/===/==|}:|||_=.......//|>&>!__!>>[+[+++++++++++[++++[+++[++[+++'+[_!##....................................................................................../=|_/..........................//.../=||||}=//=/./##!!##|#}}##|!####!#!!!!!!>[>+>>!!!!!!!!!!!!>>>>>>+>++[>>>+>>>>>>>", +">>>>>>>!>>>!>>>>_>>!>[!!>>>>[>>>>>>>>!>!!!!!!!!#!!!!|...../../.}}=#=//=|/=..///=|:/./=./|:}=///}#+>!=.........../......./=>+[[++[+[+[+++[+['+[+'+'++1+[++['+_#}...............................................................................}##>_==//......................//==::::||=&|:&|_||||:|:=/=..............}#####=}:|_#|_>+;'+!>!>!>>>+>>>>>!>!!>>>[>>>>>>>>>", +">>>>>>>>!!>>>>>>>>>+>>+[+>>>>+!>>>>>>>!!!!!!!!!>###/.....//....../=/=//./.......//./=}=.==:=|:![!>+!/...................../|++[+++'[++[++++[+['['[[++''[''[+>#=/............................................................................}>_}/.........................=:|::::|::::::==:==:&::::=:/................//######/}=||!_>>|_&>;$$$2$)2+;;$);+;++>+>+>[[>+>>", +"++>>!!>>!>!!>!>>>>>>[>>!>_!>>!_>>>!>>!!!!!!!}/./../..../||||||}/.........//....////./:|=}/./==/.====_#=.....................|>+[+[+'++'['1+'['+[''+<['++[>_::}............................................................................=||=............/..........///===:::::::::::::::::::::}=:=://////..../////...//}/##/}=/}=}/==/=}||_#![>[++;+!$$))))$;;;;;;;;3+", +"}|||!!!!!!>!###====|#>>>#/=./../.......................}||||:/}|#:==///.|}|...//}:///}///./}==/}::_/}|++/.................../}!++'+[<'['++'''[''+<'+'+<+[||}|/........................................................................../}|}.............=::=..=.//=/&:&::::|@:::::::::,::::,:==::=:::|@&:::::/::}===/......///===}=//..............////#_>_|||}}!_}==|}", +"..../././///./........=................................/:|:/.=|||#||||||=|}/..../#/.=}/...}}|==}}:|}|}_+>>/=................=}/|_'++''[+[['['+['[+'[+[+[&|||}/..........................................................................|:#:.........../:||:/=:=:}:|::=:@&:@:::::::::::::,=}=,:==:::,::,&:&&:[_::|:}=/..=//////}::|:}:||:=/.............................", +"//................../=/==///./................................=}}|:|||}}}=|}//...../|}}/.../}:||:|:}||:|';[_!|}............../}=}_['[+'<+'++<'+'''['''[>>_}/|=............................................/====}}}=.......................///..........:&:@|:/:::::::::::,:::,::::}&,:=,,=:===}====,},:::::=:=,[':=:*|==:&}:}:|:|::::&=::|::===:}://.................../", +".................}||}:}::|:|}|&}}}====/.........//=}|/.}///....|||}=}}}=}==}/}/../=//}=//...../=}=////==:_!:}_>&/............#+|/|[+'[''['[+['['[''[+'+[[[#|/......................................../=:}:|:&|&:&::}=.........................//}:=////=|&:::=|::|::::|:::,:}=&}====:=:::=,=,==,}==,},:,,:&*[**:,:|''3*:'~:=:::,::|:|::::::::::::::=/////////./=====///.", +"/.............==|&==}}=}:}::&|::____|:|||}=}}}}}|#||||||}|||}}==}//}/=}///////.../#=./}/}/}=..=|}}/..../=|:&:::|=................|+'[++['+'''+'+'+[[+___|}/......................................./==::}}}:|:::|:||&&|&|:}/.....//..=/.//=/===:}}::::::=,:::|/=::=,}@::::::::}==::::=::==,}===}=,}}=:==:::&:&::,&[~['_@[@:,,,:,},:,=::=,:==::|::|:=|:::|:::|:==|}:::::::", +":}}/..........//:}:=}}=}}|_|&}_|||=}}}:=}}}:}}}||}|}}}|}}}}|}}:}}=//=///}}}/}//===}}/}}/}}=|/=|:}|/....#}//|:||[;;#=........../=|_['''+''['''+'['+_=./............................................==:}}}:=::::}}:&&|&|&&|:&|}...|}/.=:|:_:|:||::&&&@}:::::&::/=:&:::::,:,::,::::=,=:======,=,=,=====::_|,}:=:,==[^['([[[@::=:,:,::,,,==:,=::,:|::::|::::|:}::::::|::|:|:", +":::|:/=}/......//=/=/=}}}}=}}}|}}=}=}}}|:}}|}}}}}:|}}|}#}}/==}}}}}}}}}}}/|#}}}}}}}:}=}}}=}}=}=====......../|:=:&|[;+|}.........||_''[+''+'[+[+['[|...............................................=:&=}}},&||:}::&::&|::&|&|&}.//|:=|&&:&:::&@::&&:::::::,::==:::::::::::::==:=}=:=:==}}:=,,==,=}},}=}==:==:===},=:'~[1[:&[::=,:,,:},:::,::,,,:,,:,::|&|:::|:|_|::::=::::", +"==:}:::||=../}|}:|==}===}}}}}}}}}}}}=}|}}}:}:}:}|=||}}}}#=///=}}}}}}}}}}}}}}}/}}}=}}}/}}}}}}|///........./||:::|}./||}.........}!_+'+<+<+'''__=/............/}=/==}||=..........................=:=}=,,&|:===::}::::||=.////=:|&|&&&&&::&::&:::::::,:}:::::::|::,|=,}:::},:=:=:}}=}::=:}}=}=====}=}=::==:=}=}====:[^33'@[',=:,:::,,,:,=,=,==,::::,=:&*&&['*&:&::==:::=::", +"..../=|=...../==/=/}====}======>_=}}}:}}}|,}}|}}}|}}|}==}}/=#}}/#}}}}/}/}/}/}}/}/}/}/}}/}/}=//|||=....:|//||}}||::=............./=[+'+'+''+!.................=|||+;;>}......................../=:=:}}}::&=..=|,,}::::::./:=,|&&:&:::::&|::&:::::::,:,:::::}::::::}}}}}}}:}:}}}},=}}=}}===,=}}},=}===,,===},=====,=::~[32~~'<'__|:::==:,,:,:::=,,=:_*/'3~~***&,:::::,:=//", +".................//==}=}|}=|[3'+~+[}=}}:}}|::|}|}}}=}|}|}##}#/}}}}}}}}}}}/}/}}///}}}}}}}}/.../}}////.......=|&&|}:#/............/_>''[''[[>=................./==|!|=......................../=::}}}=:&&:,/=:&:|:&=,:&:}|::|&|:&:&&&&}}}}}},}:}:}=}=:}:::}::::}:},:}}=},=}=}=:}}}=,}}=:}}====,=}=}===}:}=====,}==/====:&_&1['~2)3'_:,=,},},=,:==&}*['['*@::&:,,:::::::::.", +"........./.....==}====}|}==|'+=|}*!+3+|}}}=}}}|=|}}}#/#}}}=|}#}}}}/}}/}/}}/}}///}}/}/}}//.......//....//../../=|===..............=>[''+++>/...............................................=}::===}}:&:=..&:::}}}=::|::::&&&@::@::::}}}}=}}}|}}}===:},}:,}}}:},}}}}:}}}}:=:}=}::}}},=}}},}=,====}=:====,==,==}=}|===,==,/=/,:&*2)$33;_&:=:=::=&:~22~@&,:/==,::=|3$[_|[||=", +"..............===}}=}===}|:$|,}}_|&|>[''&__:&=}}}}}}}}}}}}}}}|}}////}}}}}}}//}/}}}}}}}/............./.:|:::}/...//................=>+'<++|...............................................:,==}}}:}},&=...=:}===}}::|&||}:&&|:&:|&}|}:}}:}|=}}}}}==:}}:|,:}}=|}}}}}}=::}}},|=}=}==}}=,====}==,=,======,=}}}=====}=}==}/=,=,=:*_^3))322$~'~_~3''$3[====:=/&'~'_'~':,//....", +"............../}=//}=}}=}}>}/}||==[_&'!';|_[!}}/}}}}}/}}}}}}}}}}//}}}}//}}/}}}}///}/}/................:====:::/..................../=:|[>/...............................................::=}}}=}}:::=/./|&::&:}:&}/}:::&:|&|}}}}|}|}|}}}}}}:}:=}}}}=}::=}}}}:}}}}}==}}:}=,}}}:}},=}}}:=::=}=======,===,==:=====}=}=======}&*[,:$'@[3~~~~32$2$[=....//=[~&:,,@://.......", +"............./..=/==}//==}/.}|=/...//.==:}'[[_}/}}}/}}}}}#}#}/#}}#}}/}}}}}}//}}}}}}}}/................=::===::/....}...................=/................................................=:}=:}},=::::=.../===//=::,:}|}}:},||}:}|:}}:}}:}}}}}==::}}:}:&}}}=}}=,==:}}=}=:::=,},}}}=:==,:,=,===,=====,|&}===|_}===========&_,:::~$_}}_&==:=::&:,.....=[[,=//.//..........", +"..................////=}=_=/............./||}|>}}}}}}/}}/}/}}}}}}}}}}}}/}}/}}}/}}///}}/............../::=:::=:}///|:=..........................................................//........=::}./=}=:,:=/...=}::,}:}||,},||}&|:=}}}}}}|}||}}}}}=}=,=:}}}}:}:=}:}}}}}=}=::}}:}}}==}=}:}}}}==,:=,===,,===:&:::&<'&:===,=|,=&[~&==,;3:=........././..../=~<=/................", +"......................}#//}/.............../:=}_|_!|}}}!}}#}}}}}}}}}/}#}/}}}}//}}/}}/#}/............../:=:=:=:=::::|:=......................................................./}}./........./..=/@}::}.=../}/:&:}}:}}}|:}||&}|}:|}|:}|}}}:}}:}=}=::|}|}=}}}}}}=:}=:=:,}}:}==::},},===,:=:==,=,=,===}==,:::[&'1['&&&:[[*&'_'':_3~:.................=='3_=.................", +"....................=|=/../.................=}=}}=}_>#}}}}}/#}}|}}}}}#/}##}}//}}/}}///}}}}=/...........===:===:/=}:=}:......................................................./=}}=..........}}=.=:}&=./..&:::::,}}}:}}|:}}|:}}},}|}|:|:}|}}|}}}|,}::}:}:,:,}}:}=}}}}}=,}}:}=,===}:}=:========}===},}::_&'^[~[*'[~[+_[[3'<::;;[=.................==;~_==.................", +".................//|=/........................=/=}}_}_|}=/}}}}}=}}}/}}}/}/}}}}}}}/}/#//}}}=}=/......../:=====:=:=:==::=......................................................./}}=..........=}===:///....:::,:}:=:}}}}|}}}|}}:|}}|}}}}}}}}}}|}=}:|&:,,:,==,,,:,::=:}:::,},=}=}===:==::,=:,==,=},&}:=::&&_*_'&*[)~1[~33~~&^[<,..................=='':&=/.................", +".............../...............................///=====}}}}}}}}}}}}}}}/#/}/}}//}}////}//====}=}}}=...==:=},}====}=}}}}}:}=.................................................=}}=/=}|........./}=}=//.===/:},}:}}}}}}:}}:|:}|:}|}|::}|||&,:,&:}}}::,:/=,=,:,,=,/:,,:=:,/=,,::==,}::,[:==&==,====,}_}&_=,:&:''**~~&[@&&&:@[[::=//................./,':,/=..................", +"...............................................=./=}=}/}==}}!}}}}/}}#}}}}}/}}//////#/}}}}/}=}=:=}=../:=,====}/===}===}===:=/............................................../}::../}:}....../==}}=}:}:=,}}::||:&}}::}&:}}}:|}|}:}}}|&,::=:=:::,::==,,,=,:,::::,/=/=:==,,=/,,,:}:=}}::&*'&=,,=},=:|=}&:::&&*'~*_**&'<*::}=:=,==}====//............/_[:}....................", +".............................................../../}==/}}===}!+>}}/}}}}}}}}}}}}//=.}}}/}/}///=,}}}=..}=}==/}/}}}}=}}}=}}==}:..............................................=}|}./}}}&}/...=}}}=:}=:}}}:=}}}}},}:,}|:,|}}}|}:}|:}:&}:|,::,,,/,=&},,=,:@,:::@::,@:,,/,,=,,,::/:,,:::&_::&[&:}=,==}}::_==:[*'[_::'~'*:*:=:,,:=:}=:}===&/............:_=.....................", +".................................................../}!_=}/}=}}:[_}}/}}}}}//}}/}//}//}}}}}}/=//}//}=//}}/}//}///}}}=}}}=}=:==..............................................==./.==}}:}..==}==}}}}=}=}}:,:}}:}}}}}}:|::,|:&}|&&:|,|:}:=,==,=,,,==,:,=::@::@:&:&:,@,::,::::@:,:,/,:_,:&&:[<&&&&}}=&:,:_|_^|,,:,,:[*,=,:,,,/,:&,=::&}/:/............///.....................", +"..................................................../}}}!}}}/==}>[|}}/}}}}}/}}/#//}/}}/}//}/}//=/}==}///}///}/}}/=}}}:}:=/=|...................................................===/=//}=}}}}}}}=:=,=:}}}}}}}}:==}:}|}:,:=&,}}}:::}::,=::},,=,=,,,:@@:::&:,:@@:&,@:,:::@&@&:,,::*&_&'*_:=,[&*[::,,=_^*&:,=,//:&'&,/,,///,,[&::='|=.:}....................................", +"...................................................../}=}=}}}}=/}!|=}}}}}}}}}}/}}}}}///}}}//}}}}////}/}///#///}}}.////....:}......................................................//=}}}}:}}}:}}}}==}=,}}=}}}}}:}::}}:}:=&:}::}:,,,=:,::::},,,::@:::@,@:&&::&::::&@:@:&::::_,|:::},:&[^|:,=:,,,}:|'3:,,,,,,,*''&:,/,,,==,,::=:[,=.==....................................", +"....................................................../}/=}/}/}==}>}/}}/}}/}/}}/}//}#/}//}/////}}#/#/}}}}//#/}}//}=/.....==:}:/................................................/===:}}:}}}:}=}}}}==,}}}=,}:=:==:,:,::}:}:==:}=:===::,::,:,@::::::@::&:@:&@:@:@:,:&@&&@:,:/,::*&&:,=&*:_*=:=,,|&&~~::=,,,/,,=@*,,//,//,,,=}==,[*=/.:.....................................", +"......................................................./}=}}}}}}}/==//}=}}#}}/}/#}}/}/#}}///.////}/}/////////=}}===......},==}/................................................/==:}}=}}=}===:==:}}=::,}:=}=}}}}}:==:,,,=:,,/,,,,:::::::@::@@&@@::@@:::@:&&:@&&@&&&@}::::::=:_&&:,=:::|::::==,,,,::,,,=,,,,,|:/,,,/,,,===:::*&=/./=.....................................", +"......................................................./}}}}==/=}}}}/}///}}}}}}}//}}/}/}////////}/}/}}}}/}}#//=/}}}/.../....../................................................../}&}:=}}}}}}:&}}}=}=}}}:},}},}::=,======/},,,:}:&@:,:=//&*&&&&*&&::&@&&&&@&&&|&::&:@:&:/,::=,/:&&&::,,::=,,:,,,,,,,,,,,,,,:,,/,/,/,,=:=,=,:&,=...}.....................................", +"......................................................./}:|}}=}}|>+!!||/}/}/#}}}}/}}}//}}}/}//}/}//////}////}/}======///........................................................../,|}}}=}=&=}}==::,}::},&:,|:,|:=.//::///=:,/,,::::/..=:_<*&*&#}&:@,&@:@:&&@&:&*&&&@:&,:::@:&,:,:,|_::=,,,,,,,:,,@,,,,,,/,:=,,,,/,/,/,===,=:/..../.....................................", +"......................................................./:|||}}}|![[_|_!/!///}/}/}}/}}}}}}}}}/.}}/.///}}/}}}/}/=////=}/............................................................/|}}}}=}}}=},:/.=}:,}:}:&|:&_:,/.../=/.,==,:,,:,:/..}&<_<*[~&##::&@,:,@:@&&&*&:@:},,::&@:&&@::@:,:,|,,,,,,,::,:,,@,,,,,:&,,,,,,/,,,==,=,=,/....=}/....................................", +".......................................................=}=}||}}=|__:|[&|>|}/}//}}}}/}}/}/}/}//}}}/}}}////}///}/...//......................................................./=/=/./=}}=}}=}}/./}}:=.=::,}},:&,:&&=..........===/,,:,}/..&_<&<'<&||@@&:,@:::,,:=:@::,:=:},::,,:,:::::,@:::,:,::,@,,@,,,,,,,,,=,,,,,,,,=:=}=,}/.....=::}/..................................", +"......................................................./}}}}||}}:}:&|+_:>_!/}}}}}/}}}}}/}}/=../}=////}//}//}/..............................................................:::=}}===}}}/..../,/}}:=///::=:&}:::&/..../....../=,=,:<&/../}&*&~<::&&:@@:,:,,:,,,,},,,&&,::,,=,=,,:@:@:@:@::@:,,@:,@,:,,,,/:&,=,/==/,=,=,=/=/...../==:,/...................................", +"......................................................./}}}}}|}}|&|=_|||'>[=/}}/#/}}/}}/}}}}/=/}}/////}////}/..............................................................:,::,::,}}=/...../=..=:::/./:::&:&:@&=/.==}==/....=,=,:,&:/..}=&&*_:::@&:&@:,,,,=,}:&=:&:}:},=,,,,:,:@:@|:@,:::@::,:::,:,,,,,:|:=}:},=,=:==..........=/......................................", +"........................................................}}:}&&}:}&%:[;>=*'>}/}}}}#}#}}}}/////#////}/}//}////...............................................................}:=@:::::=.......,:.../}::}/}:@:&,,:,/:,,,,,,::,,,,:,::*,:&...||&::@:@&:@}@::=,=}_*[*&:::::&&@&:,::,::::,&:&:@::@,@,,,,,,,,,=,:,==/=}==,,}=........./==......................................", +"........................................................}|=|}||:&&*&*&||_++}=}}}}}}}|/}}}}}}}}}/}/}}/}//}/................................................................/&@::@*^@:/../....:,.../.=://.&::///=,,,:::::,=,:,,,::@}&}::...&&*&,&&:@:@=:,::,:&'~<&:::@*&*_&@_&,}:,:,:@&::&,::::,,,,,,,,,,,=}}/./====:=/........../}:......................................", +"......................................................../}||[|:}::&:[==/__!//=}}=}}}|}}/}}}}/}/}/}////////................................................................/&*&&&^11&........//.../.=:.../@:,//,,,:@@::,:,/=,:@:&&&_&,=.../&:,}@:::::@,::::::[*=&&,**_**&&::::::,::::,:,::,:@:@:@,,,,,,:,:=/..,../=,:/..........==/......................................", +"........................................................./|}*_::&:&__=}+;[>|/}}}}}}}|}#}}//}/}}/}}/}//}/...................................................................&&@^1~%_/........./..=&_//.../:&,///,,,,:,:,,,,,:@@:@@:&~_}/../_::,::::::@::,=:::&'[@|&&*&*_@:,,,:,,::,::,,,,,,,::,,,,,/,=,=:==:/=//..==::........./}=/......................................", +"..........................................................=}}&:_&:::|}=}:+__=}}}|=}}}}}}/}}/}}=}//}////}..................................................................../,@:,=.../,//=,/,::...=....../=/.../,=,/,,,/,:@**<*@*:&*&:_&=},},:,,::,@:&:::=&}:_'<:=:&&:&:},=},,_:,,,,=,=/,=,,,,@,,,,,::,:=,==}=....====....../:}==.......................................", +"........................................................../=}&*_@:&&,}=}}|+}//}}}}}=}}}}}/}}/}/}}///////...................................................................../////=,,::@@::_@_&/...........===./....////}&&*&**_*&,&@&:_*&:,:,,,,,,}:@::=:,:_[*<3<*<::,<<:<&::&=,&,,,,,,,,,,,,/,,:,},}=}}|}}......=}=/..////==},/.......................................", +"...........................................................=}:&**&&:&:|_/|_/=}}}}}}}=}/}}}#//=}=///}/}}/...................................................................../@,:@&&:@&&*&****:/............///......}/.:**<**<_*&:::@:&::&&_:},},=,,:=::,},:~32&*&,::::&&&},::&:&:/,,/:,::::,,}:=,,::}:}:}=......==/../}=====/.........................................", +"............................................................./:&@@@::}|&/}|}/=&:,}}}}}=/}}}}}//}//////...................................................................../=,,:&****@***<*<_<:/....................../=&***<<<&@*},&&,&:,::,:,,,::,}:}::}=:=:[3$~|:::,:,&::,:,&&*~3&,,=:},,=,:,::}==}}}:}}:=...../../===,=/............................................", +"............................................................../&&&_@*:}|//====::&:}==}}=}/}/}}}/}//=......................................................................./@:,:@&**@*@**<<<'**_,:=.....=|&=........../}::_*****:&@:::<*&::::,:/,,}:,::=,::=,}:_~3~[*=,=,,:},:&<+';$3_:,,,::,,:=:,=:,,}}}}:}:......../:=/...............................................", +"...............................................................=&:@[@@=}======}:,:}}==}}}}}=///}}}/.......................................................................=::,::*@&******<<<<<**&&*:/../+<<*_|}/./././=:&&&**<*<&&&&@::<_&&},},,=,:::,,,/,:::,},*'33[*:&,,:,/:+3*'~';2<<&_,:,},,,::}:}},}}}}:=........==................................................", +".............................................................../:=/@@@&}|===}}:::&:}}:|}}}}/}/}}/}/....................................................................../=,,,,&@**<<<<<<<<'<<****@&_*}=<<<<<*<[*__}_*&@&@*&<<<<<<*&&&,:<3:::=,:,:@::&=:,,,:}::=,,@~3[<|_&,&_<'<|*'3$~;$'<},,,=,:,=}}}:&}}}|:}..........................................................", +"................................................................=:/:|:&:}=}/=}::,}:}:===///...////}....................................................................../=::,:***@*<<<<<<<<<**@@**@*[*[<<*<<<<<<<*&:*:&&@**<<<<<<<*=/=::,&&*<,,==::,@::&,=,=,:=,=,=&*~'~&:<@_}:=[;3))'+3&==,},====}=}}:::}}}}/.........................................................", +"................................................................./}/:@&::::===,::=}==............==...............................................................././=./::,&&&&**<<<<<<<<<<****_@&&&*<<<*<<<<<<<<*_&:&,&:_**<<*<<<<}..}=:::,}:}:,,::::::}:::&:==,=,,,=&33'['232$'$~~23*:====,,,},=,},}}}:|}}=..........................................................", +"................................................................./_//=@:=::=,}=}=}:............../}/............................................................././///_:::@**@*@&<<<<<<<*<<*****_@*&=&<***<<'<<<<*<&}=},:*<<**<<<<<*/./=},::}:,:==:=:/,,::&:@:,:,====,,::&3~2'33@_&:&_=,=,=,==:=}==}:},}:}|}...........................................................", +"................................................................../}/.=:=,:::====}=..............//=..................................................................&_@:::&&&::@*<<<***:@&*&*******:,<**<<<1'<'<<*&:=.}:&*@&**<*<<<*=../}=/}}}=:,}:,,:=:@&:,:,=::,:=,,=:,:,:,:,=,},,:=,,=,==,,=}:=}}}||}|=............................................................", +".................................................................../|./}},}::},==}/...............//.................................................................&<_:@&@&&@&:&@<*<*,&_&=::&&*<<*@&*<<<<*<<'<'<<<*:}./:=,::@**&**<<,&../}/,=:}}=}}==:,:&,:,,,,==:,}=,==/,:,:=:,=,==:=:,=,,,==,:==:,}}}}}/............................................................", +"....................................................................&=..=:::,}}//}..................................................................................=**::&&@&&::&&<<<<_**_*&&:&_<<<&@**<*<<*<<<'<'<<_&:=.}::,:&&&*&*<<[&//=*=..../..../==:::=,,=,=,,/::=,,:}:}:===,=,:=:,=,===:}==:==}:}=}=./=..........................................................", +"...................................................................../=./}=:=/}==}................................................................................./[<&@@&&&@&****<<<<<<*:::@*:*<<****&@&****<<''<'<*&&}./=:}::@**&&***__<_*}&}......../=::,,=,=/,/,,=,==,,}:}::}=:=,=:=:,===,,=:=,====}}/..==..........................................................", +"........................................................................./}:===/}=/.............../................................................................|<*::*@&&&*****<<<<<*,@&&&*****@*<*&,*&*<<<'<<'<**&@:}./},:&&&&*******<**_&&=.........=,==,,,,,:,=,=,===,|:|}=,=:},=:,}:=,=:=:==::==/....=/..........................................................", +"........................................................................../}===////................./............................................................./+*_**&&**<<****<<<****&@<@***:**@:,,,****<<<'<'<_<&:,}./}&,:@&****<<<<*@&&,_=........./,,=},,==,/,==:=,,===/.},:=:=,},=}}=====}==/...................................................................", +"........................................................................../=}////=/.......///........///........................................................../&'<<_*<<<<<<<*<<<<*****_@***@***&&,,:**&<<<<'<<*<<*&&:/.:}::&@&*&<<<<<****_&..........././=,/,:,,=,,,,=}/....=:=,=}==}:}==,=..//.....................................................................", +"......................../..................................................}}=}////.......==/.............../......................................................}<***<<<<<<<<<<<<<*****@:&*<*****<&::***<<'<'<'*<<**&},..=}::&***<<<<<*<<*&/............./=,==,/,,=====/......=::,:,=}}}:=}/..}=.....................................................................", +"............................................................................/}}}}/=/.....//=...............//=/....................................................=<'<<<1<<<<''1<<<<<<^***@:_*<<<<<***&*_<<1'<'<<<<__*@::...}:,&***<<<<*<<_:/............../,/,:=,/,,:==......../}:===,,:=}}}../:/........../..........................................................", +".............................................................................././}////=/////........../............................................................=<<<**<<'<<<<<<<<<*<**&,,:<<<<<<<****<&*<<'<'<<<**<*&&:&/./}:&**<<****@_=/.............../,,/,,,=//,=........../::,}==:==:=/.............=}..........................................................", +"................................................................................/}/}//////=/.......................................................................=**********<<***<****@*@:**<<<<<<<_&<<*<'<'<<'<<<<&&&&,:/./=}@&<<&_&,:}=................../,/,,,=,==...........=::=:=::}}}}==............/:=.........................................................", +"...................................................................................//.//////.//=...................................................................&***@@@@@@******<^**&@@***<***<<*<<<**<*<<<<<<<<*&*&:&:=,/.,}&@[**&&}/..................../,/,,,,=.............////:=:,:=}},=/........../==..........................................................", +".......................................................................................//}/==////................................................................./***:&,::&:@@*@*@****<***<<***<<*<***<***<*<<*****:@:@,,::}//:&&&&&://....................../,/,/==.................::=:=},==}}...........==/.........................................................", +"..........................................................................................///}///..................................................................:@:@,,,,,,::@:@@&**@<*<*<<**<<&_***@**@*@&***&@**@::@,,,,::/}}&}:/.........................,,,,,,/.................=:=::}:}===.........../==/........................................................", +"............................................................................................//=/...................................................................=,,,,/,,,,,,,,,@@@&****^<<<<***|@:::::::@:@*@@@:@:@::,,/,==:}}............................../,,/,/................./=/=::}::=}/..........///=/.......................................................", +"..............................................................................................//....................................................................=:},,,/,,,,,,,},&@::@&@******:@:@,,,:,,@@@*&,,,@:,,,::,,==://.../=_/.......................=,,,,..................==../:,::=}............/////......................................................", +"............................................................................................../}/..........//......................................................./}=}}=,}=,:=,,,,,:,:::::::*&@:&,,,/,,,,,,:,,,,,,,,,,,/,,,,::=,}__*}|=/==::::&,}}/}/==:}:,:===,:=}..................................................=~&=}::,}::::,}:=:}:}&|_|#|/.....:&_&_&........................................................................=,:@::,:,@@@@,,,,=/::,:}..................................", +"............................................................................................................=&}=}}==::&@&@:}/}/===:}}=,}==,=}................................................../<|:::}:,&},::,:::=}}:}__}.......|&&__=......................................................................./:@,@,,@@@@,@@@@,,,:=::==/.................................", +".............................................................................................................=|}:&=&,@&&@&:}=/}=}:|&@}},}====...................................................=&,::,:&:::::},,,::,}&|}........=&|@[/......................................................................,,@@@@@@@,@@@@@@@@,,:,:=}==/................................", +"............................................................................................................./[&!}|:::@@@*::=:::,}:,},==:}==/...................................................._=,:::&:&:,::=::==:=}}.........::__:....................................................................=,,@@@@@@@@@@@@@@@@@@@@@,:::,:==...............................", +"..............................................................................................................[_'_&::&&*&@@:::,=}====}}=,,}}...................................................../&}:&@&*@&::::=::,,:,:........}&|@_=................................................................./:::,,,,@@@@,@@@@@@@@@@@@@@,,:,:,:==..............//..............", +"..............................................................................................................*:,:=:@&:@&@&::::==,}===}=}=:/......................................................|:,_***&&:,}::,}:,==}/.......:&:&_.................................................................=[%1:,,,,@,,@@,@@@@@@@@@@@@@,:,}:::==/.............................", +"............................................................................................................./__|:,=,@@&@_::::}|/}=//=,}}==.......................................................*&:***@*@&&::,:},}:},=.......=|:&_.................................................................=%(%-@@,,@@,,@@@@@@@@@@@@@@@:,,,,,::}}.............................", +".............................................................................................................=*:&:=:}:@&::}=:::==}}/}=////........................................................}<&&@_***&:,:==:::==&=......./_&&}.................................................................&^1@1@,@@,,,,,@,@@@@@@@@@-@@@:,::,:=::=............................", +".............................................................................................................}[:::=,:*&:::=}::}=/}/=//............................................................}<&&<@***@:},:::,::}/.........=:=..................................................................=*@@@@@,,@@@,,,@,,@@@@@--%-@@@@,,},,:===...........................", +".............................................................................................................}_&&:=:@@&==:===:}=/=/}............................................................../_*:****&&::}:::},&/...............................................................................=,@@,@@,,,,@,,,,,@@,@@@-1%^@&&::,:,:,:}:...........................", +".............................................................................................................|^_:,::&_@:::===:}}}/=/...............................................................}*&:_&:*:@:=:,|::&................................................................................/,,@@,,@,@,,@,@,,,@@@@@-~111@@,:,=:,,,,:/..........................", +".............................................................................................................__*:==::&&@:==,=::}=///.............................................................../_*&<*&*&&@:&@::*:.................................................................................:,,,@,@,@,@,,,@,@,@,@@^~~]]^-@@@,::::,:/..........................", +"............................................................................................................/*&&:,==:::::,}}::==}=}................................................................./<*<<****&*@&&@}...................................................................................@,,,@,,,@@,,@,,,@,@@@@%1<{%(^@@,,,,}::/..........................", +"............................................................................................................=_::==::::&::::=:::=}/}.................................................................._**<**@*@&@&@}.................................................................................../,@,@,,@,@,,@@,@@@@,@@@1*@^1]--^-@:,:::...........................", +"............................................................................................................/:}_:::@&:::=::====}/..................................................................../_***&@@&@@_*=....................................................................................,,,@,@,,,,@@@,,,@@@@*@*&@&-(](((-(@,}|...........................", +"............................................................................................................,:::::@@@@:/=:===//=/.....................................................................&****@&:@&*/.....................................................................................=:@,,@,@,,,.,/./.,,@@@@,:@,^](-((^@,&/...........................", +"............................................................................................................/:<=:@@:&,:===//=/==......................................................................,:&@__@&&:/......................................................................................=:@@,:,@,,.........,^@@@,@@,@](((@@@=............................", +"............................................................................................................==&,::@&@:,====/}}//......................................................................=:::/==/........................................................................................./::://./............&/:@:,,@@-((]-@:/............................", +"............................................................................................................:&::@@@@@@&,//}/}|/.........................................................................................................................................................................//...................=:@,@-----@@&=.............................", +".........................................................................................................../|_,:::@&@&&:&}/................................................................................................................................................................................................../.=,@@@@@@:@|........................=.....", +"...........................................................................................................,,=&@,:@@@@@@@&&/....................................................................................................................................................................................................}:,@::::::......................../=....", +"........................................................................................................../::::@@&::@&@&@@_/..................................................................................................................................................................................................../=}=,}:=........................../===..", +"........................................................................................................../:_:&&@@@@,@&@@&=......................................................................................................................................................................................................../..............................=,=/..", +"........................................................................................................../:_&:@&@&&&:,/............................................................................................................................................................................................................./../..........................=....", +"..........................................................................................................,[,:&&@@@@&_............................................................................................................................................................................................................../}=}/......................./=//....", +"..........................................................................................................:[:@&::&&/,/...............................................................................................................................................................................................................}:}....................../_==......", +"..........................................................................................................=:::&*@&&=/.................................................................................................................................................................................................................=/...................../}==.......", +".........................................................................................................//:&@:&:@:/......................................................................................................................................................................................................................................./:==/........", +"........................................................................................................./=:::@:&:=........................................................................................................................................................................................................................................===}.........", +".........................................................................................................//|:@&:&=........................................................................................................................................................................................................................................./=,..........", +"......................................................................................................../:|::::::........................................................................................................................................................................................................................................../............", +".........................................................................................................=[}::@::}......................................................................................................................................................................................................................................................", +"......................................................................................................../:[::,&&:}......................................................................................................................................................................................................................................................", +"......................................................................................................../=+:::::=.......................................................................................................................................................................................................................................................", +".........................................................................................................=[::@&=/.......................................................................................................................................................................................................................................................", +".........................................................................................................:|::::/........./..............................................................................................................................................................................................................................................", +"........................................................................................................./:::::/......../...............................................................................................................................................................................................................................................", +"..........................................................................................................=&:,::/.......................................................................................................................................................................................................................................................", +".........................................................................................................../==:::=......................................................................................................................................................................................................................................................", +"............................................................................................................./===/......................................................................................................................................................................................................................................................", +"........................................................................................................................................................................................................................................................................................................................................................................", +"........................................................................................................................................................................................................................................................................................................................................................................", +"........................................................................................................................................................................................................................................................................................................................................................................", +"........................................................................................................................................................................................................................................................................................................................................................................", +"........................................................................................................................................................................................................................................................................................................................................................................", +"........................................................................................................................................................................................................................................................................................................................................................................", +".........................................................................................................................////...........................................................................................................................................................................................................................................", +"....................................................................................................................///|}}=.............................................................................................................................................................................................................................................", +"....................................................................................................................|_=/...............................................................................................................................................................././..........//...................=|............................................", +"..................................................................................................................|_||=/..............................................................................................................}&[[[!=...............................=/....////.=_!__|}}=//}_[!_#=..././/==|/..}}}|_[|:///.......................................", +"..............................................................................................................._}[>}==}/........................................................................................................./=/|_['''''+[|=/=////.............../||__[[++[>[++++[++'''''''[+['''''+[[[[+++'+''+[[+'''''+''+++[>_}//................................", +"................................................................................................................/[_/=}//.............................................................................................//......:!+[+'+'''+''''''';'+'+[++[[>........}[[+''''''''[''''''''''''''''''''''+''';+'''''''''''''''''''''''+''+++!_}/./..........................", +"............................................................................................................||/.|>++##}............................................................................................/}+[|/=.}>''<'''''''''''''''''''''''''_/.../=}_+'''''''''''''''''''''''''''''''''''''''';'''''';'''''''''''''''''''''''++++[_|_}/....................", +"........................................................................................................=...#>>|+'+++|}.................................................................///}|}/.}:}|&_||}=//=}|&_[[++'+'+[[''''''''''''''''''+'''+''''''[|#}}[[+'''''''''''';''''''''''''';''''+''''''''''''''''''''''''+;'''''+''''''''''''''''+''+[>&}}}}/............", +"......................................................................................................../|}|&[+_:'++++>}...............................................|[[}.}!}}||//|[['[+'''<+++''''''''+''''+'''<''''''''''''''+'';+'''''''''''''''''+!||_+''''''''''+'''''''''''''''''+''''''+''''';'''''''''''''''';'''''''''+'''''''''''''''''''''';'++_}/.........", +".............................................................................=}||||=................./../}|}|>_}:++''+!|...........................................=|!*++''+*''<'''+''''''''''''''''''''''''''''''''''''''''''''''''''''''+''''''''''''[>|[++'''''''''''''''''''''''+''+''''''''''';''''''''';''''''''''';''''''''''''''''''''';''''''''''+<++=.........", +"..................................................==/../............}/......}||_['[>_|___&!_|}=/...=|_//|}|||:#_[<'[+'_}........................................}[+++'+'''''''''''''''''''''''''''+';'''<'''''''''''''''''''';'''''+'''''''''''''';';''''+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';''''''';'''''''''''''';''';'<+[[[:..........", +".............................................//}|_|[+[_[>[[_|_|_||__>+!_![>_[['+''''++'++'['+'+++[[++[+[[[++++++'+'+[+&..................................../}}}[++<'+''''''''''+'''+''''''''''''''''''''''''+''+;'''''''''+''+''''+''''+;'''''+''''+'''''''''''''+'''''''+''+''+''+''''''''''''''''''';'''''''''''';+''''''''''''+''';''''''''''''''''[+[:/.............", +"..................................///=||>+++>[[+;+'+'+''''+++'++'++''[''''''+'+'''+'''+''+''''+'''+'+'[++'''''+'+'+++>_}/................................./|_[[+++;'''+''+''''''''''''''''+''''''''+'''''+''''''''''''+'''''''''''''''''''+'''''+''';''''''''''''''+''+'''''''''''''''''''+''''+';''''''';'''''';+'';'';''''''''''';''''';''''';'''';+_/................", +"............................/=}_>[++++'''''''+'''+'+'++++'+'''''''++;++'''';'''+''+'+''+''+++'++''+'+'''[;++[+[[+[>_!!>!!|!}=//......................./=|>''+[+'<''''''''''''''''''''''+'''''''''''''+''''''''''''''''''''''''''''''''''''''''''''<'''';'';'''+'''''''''''''''''';''''''';''''''''''''''''';';''''''''''''''''''''''''''''';''''''''''_.................", +"...................}=|}=//||_||[''''''+'+'+'+'+++;+;+'';'+''+++++''''+'+'++''+''+''+''+'+''''+'''+''+''+'+'[>[>!>!>>_>_>_>_!>#!##}/............../=|_[+'''[+''''''+''+'''+'''''''''+'''''''''+'''''''';'''+''''+''+'''''''''''+'''+'''''''+''''''''''''''''+''''''''''''''''''''''''''''''+'''''''';''''''''''''''''''+;''';''''''+''';'''''''''''''''+}..///...........", +"....../=|__|_#&_![[+''+++'++;+'+'+'+'''''''''+''+'+'+'++'++''+''++++'+''''+'''+''+''+'+''+'+'+++'++'+''+'''+>[>[_>_>>!#_!_>_>_>>[!!__|_||_![[[[_[+''''''''''''''''''''''''''+''+'''''';''''+'''+''''''''''''''''''''''''+'''''''''''''''''''+''''+'''+'''''''''''''''''''+''+''+'''+''+'''''''''+'''';''''''''';''''''''''''''''''''''''''''''';'''''''+!_|=//./........", +"/==&!++''+++''+'''+'+''+''+'+'''+'+''+'+'+'+'''''''+'+''+''+''++''''''+'+''++'''';+''''+'+''''''+''''++''++[+[+[[[>![[>>_!>!_>_[+'++++'+'''+''+'+'''+''''''+''+''''<''+''+'''''''''+'''''''''''''+'''''''''''''''''''+'''+'''''''''+''''''''''+'''''''+'''''''+'''+'''+'''''''''''''''''''+''+''''''''''''''''''''';'''';''''''''''''';'';'';'''';'''''''';+'+'++[_:=/..", +"+++'1''+'+'''''++''''+''+''+'''''''''+'+;''+'''''''+'+''+''''''++'+'+'''''';+''++''+'''+''++'++''+'''''+''+[_[![[[[[[['+>[>[>[>+<''+'+'''''''+''''''''+'''''''''''''+'''''''''+''''''+'''+''''''''''+''+''''+''''''+'''''''''''+''''''+''''''''''''+''''''''''''''''+'''''''''''''''''''''''''';''''''';''';''''''''''''''';';'''''''''''''''''''''''''''''''''''''+'+++", +"''+'''''''+'''+''+'+''+''+''';''''';'''''+''+''+''''+;'+;+''+'+''<''''''+'+''+;'''''''+'''''''''''+'''['''+++++[[[[[[+[['['''''''+''''''''''''';[';+'''+'''''''''+'''['''+'+'''+''''''''''''''''''''''';+''+;'''+'''''''''+'''''''''''''''''''''''''''+'''''''''''+';''''''''''+''''''''';''';'''''''''''''''''''''''';'''''''''';'';';'''''''''''''''';'''''''''+;'''''", +"'''+'+'+';''+''''''''''''''''';''''+''''''''''''+'''''++''''''''''''''+'''+''''';''''''''+''''''''';''''[;''''+'+'''''+'''''+'+'''''''+''+''';''''''''''''''+''+'''''''+''''''''''''''''''''''''''''''''''''';'''''''''''';'+';''''''''''''''''''''''''''+'''''+''''''''''+''+'''+''''+''''''''''';''''''''''';';''''''''''''';'''''''''''';'''';';'''''''''''''''''''''", +"''';';''''';'';''';';'''';'+''';''''''';'''+''''''''''''+'';'''';+'+''''';''';''+';+'''''''''+''''''';'''''''''''''+'''''''''''''''+''''''''''''';';';'+'''''''''''';''''''''''''''''+'';'''+'''+'''''''''''''''''''+'''''''''''+'''''''+'''+''+''''''''''''+''''''''''+'''''';'''''''''''''+'+''''''''''''''''''';'''''''''''''''''''''''''';''''''''''+'''''''''''''''", +"''+'''';'''''''';'''''+''''''+'';''''+'+'''''+';''+''''''''''+'''''''''''''''''''''';'+';''+''';';[''''+'''+'''''+''''''+''''';;''''';'''';'''''''''''''''';''''''+''';''''''''';''';''+'';'''''''+;<''''+''<''''''''''''''''''''''+'''''''''''''''''''''';''''''''''''''''''''''''+''''''+'''''+''';'''''';''''''''''''''''''''''''''';''''''''''''''';'';';'''';;'''''", +";';'+''''''';''''''+;';''';'';''''';;''';';+'''+;';'''';''+''';''''+'';'+'''+';''''+'';''''''''''';'''';+'''+'''';'+'+'';'+;''+'''''''+''''+'''''''''';';''''';'''''''''''+'''''++''''''+''''''''''''''''''+''+''''''';'''''+'''''''+'';'''''''''''''+'''''''';'+''+'''''''''''''''''''+''''';''''''''';''''''''''''''';''''''''''''''''';''''''''''''''''''''''''''''''", +"''''''+'''''''''+'''''''+''''''+'''+'''''''''+''''''''''+;'''+'''''''+''''+''''''+;''';''';'''''+'+''''''''''''''''''''''''''''';'''';''+''''+''+''+''''+';''';'';''+'''''''+'''''''''''''''''''''+'''+'''';'''''+'''+'''+''''''''''''''';''''''+''''''+''''''''''''''''+'''''''+'''''''''''''''''''''''''''''''''';''''''''''''''''''''''''';'';';''''''''''';'''''''''", +"''';';'+''''+''''''''''';'''''''''''''''''''''+''';''+''''+';''''';''''';';''''''''''''''''''''''''''''''';'';+''''';'''';''''+''+'''''';''''''''''''''''''+'''''+''''''';''''''+'''''''+''+'''''''''''''''''''''';'''''''''''+'''''''+'''''''''''''''''''''+'''''''+'''''''+'''''''''''''''''''''''''';''''''''''''''';'';'';'';'';''''''''''''''''''''''''';''''''''''", +"''''''''''';''''';'''''''''''''';''''''''';'''''+'''''';''''''''+''+;'''''''+'+''''''+'+''''''''';''''''''''''''+''''''''''+'''''''+''''''''''''+;''''+''''''+'''''''''''''''''''''+'''''''''+'''''''''''''''''+'+'''''+''''''''+''''''+'+''+'''''''';'''+''''''''''''''''+'''+'''''''''''+''''''';'''''''''''''''''''''''''''''''''''''''''''''''';';'''''''''''';'';''", +"'''''';';'''';''''''';''''''';''''';'''''''''''''+';'''''''''''''''''''''''''''''''''''''''+''''''''''+''''''''''''''''''''''''';'''+;'''+'''''''''+;''''''''''''''''+''+'''''''+'''''''''''''''''+''''''''+''''''''+'''''''''''''''''''''''''''+'''''''''''''+'''''''''''''''''''+'''+''''+''''''''''''';'';'';''''''''''''''''''';''''''';'';'''''''''';''''''''''''''"}; diff --git a/wmglobe/src/mycontext.c b/wmglobe/src/mycontext.c new file mode 100644 index 0000000..bf89759 --- /dev/null +++ b/wmglobe/src/mycontext.c @@ -0,0 +1,556 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * mycontext.c - an adaptation of wrlib for use in wmglobe + * initial source taken in WindowMaker-0.20.3/wrlib : + */ +/* context.c - X context management + * Raster graphics library + * + * Copyright (c) 1997 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * #include + */ +#include "wmglobe.h" + +/* + * #include + * #include + * #include + * + * #include + * #include + * #include + * #include + * + * #include + * + * #include "wraster.h" + */ + +static Bool bestContext(Display * dpy, int screen_number, RContext * context); + +static RContextAttributes DEFAULT_CONTEXT_ATTRIBS = +{ + RC_DefaultVisual, /* flags */ + 0, /* render_mode */ + 0, /* colors_per_channel */ + 0, + 0, + 0, + 0, + 0 /* NO use_shared_memory */ +}; + + +static XColor * + allocatePseudoColor(RContext * ctx) +{ + XColor *colors; + XColor avcolors[256]; + int avncolors; + int i, ncolors, r, g, b; + int retries; + int cpc = ctx->attribs->colors_per_channel; + + ncolors = cpc * cpc * cpc; + + if (ncolors > (1 << ctx->depth)) { + /* reduce colormap size */ + cpc = ctx->attribs->colors_per_channel = 1 << ((int) ctx->depth / 3); + ncolors = cpc * cpc * cpc; + } + assert(cpc >= 2 && ncolors <= (1 << ctx->depth)); + + colors = malloc(sizeof(XColor) * ncolors); + if (!colors) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + i = 0; + + if ((ctx->attribs->flags & RC_GammaCorrection) && ctx->attribs->rgamma > 0 + && ctx->attribs->ggamma > 0 && ctx->attribs->bgamma > 0) { + double rg, gg, bg; + double tmp; + + /* do gamma correction */ + rg = 1.0 / ctx->attribs->rgamma; + gg = 1.0 / ctx->attribs->ggamma; + bg = 1.0 / ctx->attribs->bgamma; + for (r = 0; r < cpc; r++) { + for (g = 0; g < cpc; g++) { + for (b = 0; b < cpc; b++) { + colors[i].red = (r * 0xffff) / (cpc - 1); + colors[i].green = (g * 0xffff) / (cpc - 1); + colors[i].blue = (b * 0xffff) / (cpc - 1); + colors[i].flags = DoRed | DoGreen | DoBlue; + + tmp = (double) colors[i].red / 65536.0; + colors[i].red = (unsigned short) (65536.0 * pow(tmp, rg)); + + tmp = (double) colors[i].green / 65536.0; + colors[i].green = (unsigned short) (65536.0 * pow(tmp, gg)); + + tmp = (double) colors[i].blue / 65536.0; + colors[i].blue = (unsigned short) (65536.0 * pow(tmp, bg)); + + i++; + } + } + } + + } else { + for (r = 0; r < cpc; r++) { + for (g = 0; g < cpc; g++) { + for (b = 0; b < cpc; b++) { + colors[i].red = (r * 0xffff) / (cpc - 1); + colors[i].green = (g * 0xffff) / (cpc - 1); + colors[i].blue = (b * 0xffff) / (cpc - 1); + colors[i].flags = DoRed | DoGreen | DoBlue; + i++; + } + } + } + } + /* try to allocate the colors */ + for (i = 0; i < ncolors; i++) { + if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) { + colors[i].flags = 0; /* failed */ + } else { + colors[i].flags = DoRed | DoGreen | DoBlue; + } + } + /* try to allocate close values for the colors that couldn't + * be allocated before */ + avncolors = (1 << ctx->depth > 256 ? 256 : 1 << ctx->depth); + for (i = 0; i < avncolors; i++) + avcolors[i].pixel = i; + + XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors); + + for (i = 0; i < ncolors; i++) { + if (colors[i].flags == 0) { + int j; + unsigned long cdiff = 0xffffffff, diff; + unsigned long closest = 0; + + retries = 2; + + while (retries--) { + /* find closest color */ + for (j = 0; j < avncolors; j++) { + r = (colors[i].red - avcolors[i].red) >> 8; + g = (colors[i].green - avcolors[i].green) >> 8; + b = (colors[i].blue - avcolors[i].blue) >> 8; + diff = r * r + g * g + b * b; + if (diff < cdiff) { + cdiff = diff; + closest = j; + } + } + /* allocate closest color found */ + colors[i].red = avcolors[closest].red; + colors[i].green = avcolors[closest].green; + colors[i].blue = avcolors[closest].blue; + if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) { + colors[i].flags = DoRed | DoGreen | DoBlue; + break; /* succeeded, don't need to retry */ + } +#ifdef DEBUG + printf("close color allocation failed. Retrying...\n"); +#endif + } + } + } + return colors; +} + + +static XColor * + allocateGrayScale(RContext * ctx) +{ + XColor *colors; + XColor avcolors[256]; + int avncolors; + int i, ncolors, r, g, b; + int retries; + int cpc = ctx->attribs->colors_per_channel; + + ncolors = cpc * cpc * cpc; + + if (ctx->vclass == StaticGray) { + /* we might as well use all grays */ + ncolors = 1 << ctx->depth; + } else { + if (ncolors > (1 << ctx->depth)) { + /* reduce colormap size */ + cpc = ctx->attribs->colors_per_channel = 1 << ((int) ctx->depth / 3); + ncolors = cpc * cpc * cpc; + } + assert(cpc >= 2 && ncolors <= (1 << ctx->depth)); + } + + if (ncolors >= 256 && ctx->vclass == StaticGray) { + /* don't need dithering for 256 levels of gray in StaticGray visual */ + ctx->attribs->render_mode = RM_MATCH; + } + colors = malloc(sizeof(XColor) * ncolors); + if (!colors) { + RErrorCode = RERR_NOMEMORY; + return False; + } + for (i = 0; i < ncolors; i++) { + colors[i].red = (i * 0xffff) / (ncolors - 1); + colors[i].green = (i * 0xffff) / (ncolors - 1); + colors[i].blue = (i * 0xffff) / (ncolors - 1); + colors[i].flags = DoRed | DoGreen | DoBlue; + } + /* try to allocate the colors */ + for (i = 0; i < ncolors; i++) { +#ifdef DEBUG + printf("trying:%x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue); +#endif + if (!XAllocColor(ctx->dpy, ctx->cmap, &(colors[i]))) { + colors[i].flags = 0; /* failed */ +#ifdef DEBUG + printf("failed:%x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue); +#endif + } else { + colors[i].flags = DoRed | DoGreen | DoBlue; +#ifdef DEBUG + printf("success:%x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue); +#endif + } + } + /* try to allocate close values for the colors that couldn't + * be allocated before */ + avncolors = (1 << ctx->depth > 256 ? 256 : 1 << ctx->depth); + for (i = 0; i < avncolors; i++) + avcolors[i].pixel = i; + + XQueryColors(ctx->dpy, ctx->cmap, avcolors, avncolors); + + for (i = 0; i < ncolors; i++) { + if (colors[i].flags == 0) { + int j; + unsigned long cdiff = 0xffffffff, diff; + unsigned long closest = 0; + + retries = 2; + + while (retries--) { + /* find closest color */ + for (j = 0; j < avncolors; j++) { + r = (colors[i].red - avcolors[i].red) >> 8; + g = (colors[i].green - avcolors[i].green) >> 8; + b = (colors[i].blue - avcolors[i].blue) >> 8; + diff = r * r + g * g + b * b; + if (diff < cdiff) { + cdiff = diff; + closest = j; + } + } + /* allocate closest color found */ +#ifdef DEBUG + printf("best match:%x,%x,%x => %x,%x,%x\n", colors[i].red, colors[i].green, colors[i].blue, avcolors[closest].red, avcolors[closest].green, avcolors[closest].blue); +#endif + colors[i].red = avcolors[closest].red; + colors[i].green = avcolors[closest].green; + colors[i].blue = avcolors[closest].blue; + if (XAllocColor(ctx->dpy, ctx->cmap, &colors[i])) { + colors[i].flags = DoRed | DoGreen | DoBlue; + break; /* succeeded, don't need to retry */ + } +#ifdef DEBUG + printf("close color allocation failed. Retrying...\n"); +#endif + } + } + } + return colors; +} + + +static char * + mygetenv(char *var, int scr) +{ + char *p; + char varname[64]; + + sprintf(varname, "%s%i", var, scr); + p = getenv(varname); + if (!p) { + p = getenv(var); + } + return p; +} + + +static void gatherconfig(RContext * context, int screen_n) +{ + char *ptr; + + ptr = mygetenv("WRASTER_GAMMA", screen_n); + if (ptr) { + float g1, g2, g3; + if (sscanf(ptr, "%f/%f/%f", &g1, &g2, &g3) != 3 + || g1 <= 0.0 || g2 <= 0.0 || g3 <= 0.0) { + printf("wrlib: invalid value(s) for gamma correction \"%s\"\n", + ptr); + } else { + context->attribs->flags |= RC_GammaCorrection; + context->attribs->rgamma = g1; + context->attribs->ggamma = g2; + context->attribs->bgamma = g3; + } + } + ptr = mygetenv("WRASTER_COLOR_RESOLUTION", screen_n); + if (ptr) { + int i; + if (sscanf(ptr, "%d", &i) != 1 || i < 2 || i > 6) { + printf("wrlib: invalid value for color resolution \"%s\"\n", ptr); + } else { + context->attribs->flags |= RC_ColorsPerChannel; + context->attribs->colors_per_channel = i; + } + } +} + + +static void getColormap(RContext * context, int screen_number) +{ + Colormap cmap = None; + XStandardColormap *cmaps; + int ncmaps, i; + + if (XGetRGBColormaps(context->dpy, + RootWindow(context->dpy, screen_number), + &cmaps, &ncmaps, XA_RGB_DEFAULT_MAP)) { + for (i = 0; i < ncmaps; ++i) { + if (cmaps[i].visualid == context->visual->visualid) { + puts("ACHOU"); + cmap = cmaps[i].colormap; + break; + } + } + XFree(cmaps); + } + if (cmap == None) { + XColor color; + + cmap = XCreateColormap(context->dpy, + RootWindow(context->dpy, screen_number), + context->visual, AllocNone); + + color.red = color.green = color.blue = 0; + XAllocColor(context->dpy, cmap, &color); + context->black = color.pixel; + + color.red = color.green = color.blue = 0xffff; + XAllocColor(context->dpy, cmap, &color); + context->white = color.pixel; + + } + context->cmap = cmap; +} + + +static int count_offset(unsigned long mask) +{ + int i; + + i = 0; + while ((mask & 1) == 0) { + i++; + mask = mask >> 1; + } + return i; +} + + +RContext * + myRCreateContext(Display * dpy, int screen_number, RContextAttributes * attribs) +{ + RContext *context; + XGCValues gcv; + + + context = malloc(sizeof(RContext)); + if (!context) { + RErrorCode = RERR_NOMEMORY; + return NULL; + } + memset(context, 0, sizeof(RContext)); + + context->dpy = dpy; + + context->screen_number = screen_number; + + context->attribs = malloc(sizeof(RContextAttributes)); + if (!context->attribs) { + free(context); + RErrorCode = RERR_NOMEMORY; + return NULL; + } + if (!attribs) + *context->attribs = DEFAULT_CONTEXT_ATTRIBS; + else + *context->attribs = *attribs; + + /* get configuration from environment variables */ + gatherconfig(context, screen_number); + + if ((context->attribs->flags & RC_VisualID)) { + XVisualInfo *vinfo, templ; + int nret; + + templ.screen = screen_number; + templ.visualid = context->attribs->visualid; + vinfo = XGetVisualInfo(context->dpy, VisualIDMask | VisualScreenMask, + &templ, &nret); + if (!vinfo || nret == 0) { + free(context); + RErrorCode = RERR_BADVISUALID; + return NULL; + } + if (vinfo[0].visual == DefaultVisual(dpy, screen_number)) { + context->attribs->flags |= RC_DefaultVisual; + } else { + XSetWindowAttributes attr; + unsigned long mask; + + context->visual = vinfo[0].visual; + context->depth = vinfo[0].depth; + context->vclass = vinfo[0].class; + getColormap(context, screen_number); + attr.colormap = context->cmap; + attr.override_redirect = True; + attr.border_pixel = 0; + attr.background_pixel = 0; + mask = CWBorderPixel | CWColormap | CWOverrideRedirect | CWBackPixel; + context->drawable = + XCreateWindow(dpy, RootWindow(dpy, screen_number), 1, 1, + 1, 1, 0, context->depth, CopyFromParent, + context->visual, mask, &attr); + /* XSetWindowColormap(dpy, context->drawable, attr.colormap); */ + } + XFree(vinfo); + } + /* use default */ + if (!context->visual) { + if ((context->attribs->flags & RC_DefaultVisual) + || !bestContext(dpy, screen_number, context)) { + context->visual = DefaultVisual(dpy, screen_number); + context->depth = DefaultDepth(dpy, screen_number); + context->cmap = DefaultColormap(dpy, screen_number); + context->drawable = RootWindow(dpy, screen_number); + context->black = BlackPixel(dpy, screen_number); + context->white = WhitePixel(dpy, screen_number); + context->vclass = context->visual->class; + } + } + gcv.function = GXcopy; + gcv.graphics_exposures = False; + context->copy_gc = XCreateGC(dpy, context->drawable, GCFunction + | GCGraphicsExposures, &gcv); + + if (context->vclass == PseudoColor || context->vclass == StaticColor) { + context->colors = allocatePseudoColor(context); + if (!context->colors) { + return NULL; + } + } else if (context->vclass == GrayScale || context->vclass == StaticGray) { + context->colors = allocateGrayScale(context); + if (!context->colors) { + return NULL; + } + } else if (context->vclass == TrueColor) { + /* calc offsets to create a TrueColor pixel */ + context->red_offset = count_offset(context->visual->red_mask); + context->green_offset = count_offset(context->visual->green_mask); + context->blue_offset = count_offset(context->visual->blue_mask); + /* disable dithering on 24 bits visuals */ + if (context->depth >= 24) + context->attribs->render_mode = RM_MATCH; + } + /* check avaiability of MIT-SHM */ + + return context; +} + + +static Bool + bestContext(Display * dpy, int screen_number, RContext * context) +{ + XVisualInfo *vinfo = NULL, rvinfo; + int best = -1, numvis, i; + long flags; + XSetWindowAttributes attr; + + rvinfo.class = TrueColor; + rvinfo.screen = screen_number; + flags = VisualClassMask | VisualScreenMask; + + vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis); + if (vinfo) { /* look for a TrueColor, 24-bit or more (pref 24) */ + for (i = numvis - 1, best = -1; i >= 0; i--) { + if (vinfo[i].depth == 24) + best = i; + else if (vinfo[i].depth > 24 && best < 0) + best = i; + } + } +#if 0 + if (best == -1) { /* look for a DirectColor, 24-bit or more (pref 24) */ + rvinfo.class = DirectColor; + if (vinfo) + XFree((char *) vinfo); + vinfo = XGetVisualInfo(dpy, flags, &rvinfo, &numvis); + if (vinfo) { + for (i = 0, best = -1; i < numvis; i++) { + if (vinfo[i].depth == 24) + best = i; + else if (vinfo[i].depth > 24 && best < 0) + best = i; + } + } + } +#endif + if (best > -1) { + context->visual = vinfo[best].visual; + context->depth = vinfo[best].depth; + context->vclass = vinfo[best].class; + getColormap(context, screen_number); + attr.colormap = context->cmap; + attr.override_redirect = True; + attr.border_pixel = 0; + context->drawable = + XCreateWindow(dpy, RootWindow(dpy, screen_number), + 1, 1, 1, 1, 0, context->depth, + CopyFromParent, context->visual, + CWBorderPixel | CWColormap | CWOverrideRedirect, &attr); +/* XSetWindowColormap(dpy, context->drawable, context->cmap); */ + } + if (vinfo) + XFree((char *) vinfo); + + if (best < 0) + return False; + else + return True; +} diff --git a/wmglobe/src/myconvert.c b/wmglobe/src/myconvert.c new file mode 100644 index 0000000..bbb906b --- /dev/null +++ b/wmglobe/src/myconvert.c @@ -0,0 +1,578 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * myconvert.c - an adaptation of wrlib for use in wmglobe + * initial source taken in WindowMaker-0.20.3/wrlib : + */ + +/* convert.c - convert RImage to Pixmap + * Raster graphics library + * + * Copyright (c) 1997 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * #include + */ +#include "wmglobe.h" + +typedef struct RConversionTable { + unsigned short table[256]; + unsigned short index; + struct RConversionTable *next; +} RConversionTable; + + +static RConversionTable *conversionTable = NULL; +static RConversionTable *pif[3]; +static short *re, *ge, *be; +static short *nre, *nge, *nbe; +static RXImage *ximgok; + +void initmyconvert() +{ + pif[0] = (RConversionTable *) malloc(sizeof(RConversionTable)); + pif[1] = (RConversionTable *) malloc(sizeof(RConversionTable)); + pif[2] = (RConversionTable *) malloc(sizeof(RConversionTable)); + re = (short *) malloc((DIAMETRE + 2) * sizeof(short)); + ge = (short *) malloc((DIAMETRE + 2) * sizeof(short)); + be = (short *) malloc((DIAMETRE + 2) * sizeof(short)); + nre = (short *) malloc((DIAMETRE + 2) * sizeof(short)); + nge = (short *) malloc((DIAMETRE + 2) * sizeof(short)); + nbe = (short *) malloc((DIAMETRE + 2) * sizeof(short)); + ximgok = NULL; + return; +} + + + +static unsigned short * + computeTable(unsigned short mask, int hop) +{ + RConversionTable *tmp = conversionTable; + int i; + + tmp = pif[hop]; + + for (i = 0; i < 256; i++) + tmp->table[i] = (i * mask + 0x7f) / 0xff; + + tmp->index = mask; + return tmp->table; +} + + +static RXImage * + image2TrueColor(RContext * ctx, RImage * image) +{ + RXImage *ximg; + register int x, y, r, g, b; + unsigned char *red, *grn, *blu; + unsigned long pixel; + unsigned short rmask, gmask, bmask; + unsigned short roffs, goffs, boffs; + unsigned short *rtable, *gtable, *btable; + int ofs; + + if (ximgok == NULL) + ximgok = RCreateXImage(ctx, ctx->depth, image->width, image->height); + + ximg = ximgok; + if (!ximg) { + puts("err "); + return NULL; + } + red = image->data[0]; + grn = image->data[1]; + blu = image->data[2]; + + roffs = ctx->red_offset; + goffs = ctx->green_offset; + boffs = ctx->blue_offset; + + rmask = ctx->visual->red_mask >> roffs; + gmask = ctx->visual->green_mask >> goffs; + bmask = ctx->visual->blue_mask >> boffs; + + + + rtable = computeTable(rmask, 0); + gtable = computeTable(gmask, 1); + btable = computeTable(bmask, 2); + + if (rtable == NULL || gtable == NULL || btable == NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + if (ctx->attribs->render_mode == RM_MATCH) { + /* fake match */ +#ifdef DEBUG + puts("true color match"); +#endif + for (y = 0, ofs = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++, ofs++) { + /* reduce pixel */ + r = rtable[red[ofs]]; + g = gtable[grn[ofs]]; + b = btable[blu[ofs]]; + pixel = (r << roffs) | (g << goffs) | (b << boffs); + XPutPixel(ximg->image, x, y, pixel); + } + } + } else { + /* dither */ + short *rerr, *gerr, *berr; + short *nrerr, *ngerr, *nberr; + short *terr; + int rer, ger, ber; + const int dr = 0xff / rmask; + const int dg = 0xff / gmask; + const int db = 0xff / bmask; + +#ifdef DEBUG + puts("true color dither"); +#endif + rerr = re; + gerr = ge; + berr = be; + nrerr = nre; + ngerr = nge; + nberr = nbe; + + if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + for (x = 0; x < image->width; x++) { + + rerr[x] = red[x]; + gerr[x] = grn[x]; + berr[x] = blu[x]; + } + rerr[x] = gerr[x] = berr[x] = 0; + /* convert and dither the image to XImage */ + for (y = 0, ofs = 0; y < image->height; y++) { + if (y < image->height - 1) { + int x1; + for (x = 0, x1 = ofs + image->width; x < image->width; x++, x1++) { + nrerr[x] = red[x1]; + ngerr[x] = grn[x1]; + nberr[x] = blu[x1]; + } + /* last column */ + x1--; + nrerr[x] = red[x1]; + ngerr[x] = grn[x1]; + nberr[x] = blu[x1]; + } + for (x = 0; x < image->width; x++) { + /* reduce pixel */ + if (rerr[x] > 0xff) + rerr[x] = 0xff; + else if (rerr[x] < 0) + rerr[x] = 0; + if (gerr[x] > 0xff) + gerr[x] = 0xff; + else if (gerr[x] < 0) + gerr[x] = 0; + if (berr[x] > 0xff) + berr[x] = 0xff; + else if (berr[x] < 0) + berr[x] = 0; + + r = rtable[rerr[x]]; + g = gtable[gerr[x]]; + b = btable[berr[x]]; + + pixel = (r << roffs) | (g << goffs) | (b << boffs); + XPutPixel(ximg->image, x, y, pixel); + /* calc error */ + rer = rerr[x] - r * dr; + ger = gerr[x] - g * dg; + ber = berr[x] - b * db; + + /* distribute error */ + r = (rer * 3) / 8; + g = (ger * 3) / 8; + b = (ber * 3) / 8; + /* x+1, y */ + rerr[x + 1] += r; + gerr[x + 1] += g; + berr[x + 1] += b; + /* x, y+1 */ + nrerr[x] += r; + ngerr[x] += g; + nberr[x] += b; + /* x+1, y+1 */ + nrerr[x + 1] += rer - 2 * r; + ngerr[x + 1] += ger - 2 * g; + nberr[x + 1] += ber - 2 * b; + } + ofs += image->width; + /* skip to next line */ + terr = rerr; + rerr = nrerr; + nrerr = terr; + + terr = gerr; + gerr = ngerr; + ngerr = terr; + + terr = berr; + berr = nberr; + nberr = terr; + } + } + return ximg; +} + + +static RXImage * + image2PseudoColor(RContext * ctx, RImage * image) +{ + RXImage *ximg; + register int x, y, r, g, b; + unsigned char *red, *grn, *blu; + unsigned long pixel; + const int cpc = ctx->attribs->colors_per_channel; + const unsigned short rmask = cpc - 1; /* different sizes could be used */ + const unsigned short gmask = rmask; /* for r,g,b */ + const unsigned short bmask = rmask; + unsigned short *rtable, *gtable, *btable; + const int cpccpc = cpc * cpc; + unsigned char *data; + int ofs; + /*register unsigned char maxrgb = 0xff; */ + + if (ximgok == NULL) + ximgok = RCreateXImage(ctx, ctx->depth, image->width, image->height); + + ximg = ximgok; + + if (!ximg) { + puts("err psc"); + return NULL; + } + red = image->data[0]; + grn = image->data[1]; + blu = image->data[2]; + + data = ximg->image->data; + + /* Tables are same at the moment because rmask==gmask==bmask. */ + rtable = computeTable(rmask, 0); + gtable = computeTable(gmask, 1); + btable = computeTable(bmask, 2); + + if (rtable == NULL || gtable == NULL || btable == NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + if (ctx->attribs->render_mode == RM_MATCH) { + /* fake match */ +#ifdef DEBUG + printf("pseudo color match with %d colors per channel\n", cpc); +#endif + for (y = 0, ofs = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++, ofs++) { + /* reduce pixel */ + r = rtable[red[ofs]]; + g = gtable[grn[ofs]]; + b = btable[blu[ofs]]; + pixel = r * cpccpc + g * cpc + b; + /*data[ofs] = ctx->colors[pixel].pixel; */ + XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel); + } + } + } else { + /* dither */ + short *rerr, *gerr, *berr; + short *nrerr, *ngerr, *nberr; + short *terr; + int rer, ger, ber; + const int dr = 0xff / rmask; + const int dg = 0xff / gmask; + const int db = 0xff / bmask; + +#ifdef DEBUG + printf("pseudo color dithering with %d colors per channel\n", cpc); +#endif + rerr = re; + gerr = ge; + berr = be; + nrerr = nre; + ngerr = nge; + nberr = nbe; + if (!rerr || !gerr || !berr || !nrerr || !ngerr || !nberr) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + for (x = 0; x < image->width; x++) { + rerr[x] = red[x]; + gerr[x] = grn[x]; + berr[x] = blu[x]; + } + rerr[x] = gerr[x] = berr[x] = 0; + /* convert and dither the image to XImage */ + for (y = 0, ofs = 0; y < image->height; y++) { + if (y < image->height - 1) { + int x1; + for (x = 0, x1 = ofs + image->width; x < image->width; x++, x1++) { + nrerr[x] = red[x1]; + ngerr[x] = grn[x1]; + nberr[x] = blu[x1]; + } + /* last column */ + x1--; + nrerr[x] = red[x1]; + ngerr[x] = grn[x1]; + nberr[x] = blu[x1]; + } + for (x = 0; x < image->width; x++, ofs++) { + /* reduce pixel */ + if (rerr[x] > 0xff) + rerr[x] = 0xff; + else if (rerr[x] < 0) + rerr[x] = 0; + if (gerr[x] > 0xff) + gerr[x] = 0xff; + else if (gerr[x] < 0) + gerr[x] = 0; + if (berr[x] > 0xff) + berr[x] = 0xff; + else if (berr[x] < 0) + berr[x] = 0; + + r = rtable[rerr[x]]; + g = gtable[gerr[x]]; + b = btable[berr[x]]; + + pixel = r * cpccpc + g * cpc + b; + /*data[ofs] = ctx->colors[pixel].pixel; */ + XPutPixel(ximg->image, x, y, ctx->colors[pixel].pixel); + + /* calc error */ + rer = rerr[x] - r * dr; + ger = gerr[x] - g * dg; + ber = berr[x] - b * db; + + /* distribute error */ + rerr[x + 1] += (rer * 7) / 16; + gerr[x + 1] += (ger * 7) / 16; + berr[x + 1] += (ber * 7) / 16; + + nrerr[x] += (rer * 5) / 16; + ngerr[x] += (ger * 5) / 16; + nberr[x] += (ber * 5) / 16; + + if (x > 0) { + nrerr[x - 1] += (rer * 3) / 16; + ngerr[x - 1] += (ger * 3) / 16; + nberr[x - 1] += (ber * 3) / 16; + } + nrerr[x + 1] += rer / 16; + ngerr[x + 1] += ger / 16; + nberr[x + 1] += ber / 16; + } + /* skip to next line */ + terr = rerr; + rerr = nrerr; + nrerr = terr; + + terr = gerr; + gerr = ngerr; + ngerr = terr; + + terr = berr; + berr = nberr; + nberr = terr; + } + } + ximg->image->data = (char *) data; + + return ximg; +} + + +static RXImage * + image2GrayScale(RContext * ctx, RImage * image) +{ + RXImage *ximg; + register int x, y, g; + unsigned char *red, *grn, *blu; + const int cpc = ctx->attribs->colors_per_channel; + unsigned short gmask; + unsigned short *table; + unsigned char *data; + int ofs; + /*register unsigned char maxrgb = 0xff; */ + + if (ximgok == NULL) + ximgok = RCreateXImage(ctx, ctx->depth, image->width, image->height); + + ximg = ximgok; + + if (!ximg) { + puts("error!"); + return NULL; + } + red = image->data[0]; + grn = image->data[1]; + blu = image->data[2]; + + data = ximg->image->data; + + if (ctx->vclass == StaticGray) + gmask = (1 << ctx->depth) - 1; /* use all grays */ + else + gmask = cpc * cpc * cpc - 1; + + table = computeTable(gmask, 0); + + if (table == NULL) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + if (ctx->attribs->render_mode == RM_MATCH) { + /* fake match */ +#ifdef DEBUG + printf("grayscale match with %d colors per channel\n", cpc); +#endif + for (y = 0, ofs = 0; y < image->height; y++) { + for (x = 0; x < image->width; x++, ofs++) { + /* reduce pixel */ + g = table[(red[ofs] * 30 + grn[ofs] * 59 + blu[ofs] * 11) / 100]; + + /*data[ofs] = ctx->colors[g].pixel; */ + XPutPixel(ximg->image, x, y, ctx->colors[g].pixel); + } + } + } else { + /* dither */ + short *gerr; + short *ngerr; + short *terr; + int ger; + const int dg = 0xff / gmask; + +#ifdef DEBUG + printf("grayscale dither with %d colors per channel\n", cpc); +#endif + gerr = ge; + ngerr = nge; + if (!gerr || !ngerr) { + RErrorCode = RERR_NOMEMORY; + RDestroyXImage(ctx, ximg); + return NULL; + } + for (x = 0; x < image->width; x++) { + gerr[x] = (red[x] * 30 + grn[x] * 59 + blu[x] * 11) / 100; + } + gerr[x] = 0; + /* convert and dither the image to XImage */ + for (y = 0, ofs = 0; y < image->height; y++) { + if (y < image->height - 1) { + int x1; + for (x = 0, x1 = ofs + image->width; x < image->width; x++, x1++) { + ngerr[x] = (red[x1] * 30 + grn[x1] * 59 + blu[x1] * 11) / 100; + } + /* last column */ + x1--; + ngerr[x] = (red[x1] * 30 + grn[x1] * 59 + blu[x1] * 11) / 100; + } + for (x = 0; x < image->width; x++, ofs++) { + /* reduce pixel */ + if (gerr[x] > 0xff) + gerr[x] = 0xff; + else if (gerr[x] < 0) + gerr[x] = 0; + + g = table[gerr[x]]; + + /*data[ofs] = ctx->colors[g].pixel; */ + XPutPixel(ximg->image, x, y, ctx->colors[g].pixel); + /* calc error */ + ger = gerr[x] - g * dg; + + /* distribute error */ + g = (ger * 3) / 8; + /* x+1, y */ + gerr[x + 1] += g; + /* x, y+1 */ + ngerr[x] += g; + /* x+1, y+1 */ + ngerr[x + 1] += ger - 2 * g; + } + /* skip to next line */ + terr = gerr; + gerr = ngerr; + ngerr = terr; + } + } + ximg->image->data = (char *) data; + + return ximg; +} + + + +int myRConvertImage(RContext * context, RImage * image, Pixmap * pixmap) +{ + RXImage *ximg = NULL; + + + assert(context != NULL); + assert(image != NULL); + assert(pixmap != NULL); + + /* clear error message */ + if (context->vclass == TrueColor) + ximg = image2TrueColor(context, image); + else if (context->vclass == PseudoColor || context->vclass == StaticColor) + ximg = image2PseudoColor(context, image); + else if (context->vclass == GrayScale || context->vclass == StaticGray) + ximg = image2GrayScale(context, image); + + if (!ximg) { +#ifdef C_ALLOCA + alloca(0); +#endif + return False; + } +/* + * *pixmap = XCreatePixmap(context->dpy, context->drawable, image->width, + * image->height, context->depth); + */ + + + RPutXImage(context, *pixmap, context->copy_gc, ximg, 0, 0, 0, 0, + image->width, image->height); + + +/* + * RDestroyXImage(context, ximg); + */ + +#ifdef C_ALLOCA + + alloca(0); +#endif + return True; +} diff --git a/wmglobe/src/rend.c b/wmglobe/src/rend.c new file mode 100644 index 0000000..f398fb8 --- /dev/null +++ b/wmglobe/src/rend.c @@ -0,0 +1,703 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************/ +/* this code is based on XGlobe : + + renderer.cpp + * + * + * This file is part of XGlobe. See README for details. + * + * Copyright (C) 1998 Thorsten Scheuermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public Licenses as published by + * the Free Software Foundation. + *************************************************************************** */ + + +#include "wmglobe.h" + +static RColor mygetMapColorLinear + (double longitude, double latitude, double angle); + +/* + * static RColor getMapColor(double longitude, double latitude, double angle); + */ + +static void randomPosition(); +void setViewPos(double lat, double lon); +static void myRPutPixel(int x, int y, RColor * color); +static void getquarter(RImage * image, int x, int y, MPO * m[4], int dx, int dy); +static void updateTime(int force); +static struct timeval timeaccel(struct timeval t); + +/* ------------------------------------------------------------------------ */ +struct timeval timeaccel(struct timeval t) +{ + struct timeval at; + double rr; + + t = diftimev(t, tini); + rr = floor((double) t.tv_sec * time_multi + (double) t.tv_usec * time_multi / 1000000.); +/*** something bad may appen if time_multi=max after 41 minutes (overflow) ***/ + while (rr > (double) LONG_MAX) + rr -= (2.0 * (double) LONG_MAX + 1.0); + at.tv_sec = (int) rr; + at.tv_usec = (int) (t.tv_usec * time_multi) % 1000000; + return addtimev(at, tbase); +} +/* ------------------------------------------------------------------------ */ +static void myRPutPixel(int x, int y, RColor * color) +{ + int ofs; + unsigned char *sr, *sg, *sb; + + ofs = y * DIAMETRE + x; + sr = small->data[0] + ofs; + sg = small->data[1] + ofs; + sb = small->data[2] + ofs; + + *sr = color->red; + *sg = color->green; + *sb = color->blue; + return; +} +/* ------------------------------------------------------------------------ */ +static void getquarter(RImage * image, int x, int y, MPO * m[4], int dx, int dy) +{ + int xx; + register int ofs; + +/*** hope this is faster than calculation with floats .... ****/ + + x %= image->width; + xx = x; + y %= image->height; + ofs = y * image->width + x; + m[0]->r = image->data[0][ofs]; + m[0]->g = image->data[1][ofs]; + m[0]->b = image->data[2][ofs]; + + xx++; + xx %= image->width; + ofs = y * image->width + xx; + m[1]->r = image->data[0][ofs]; + m[1]->g = image->data[1][ofs]; + m[1]->b = image->data[2][ofs]; + + y++; + y %= image->height; + ofs = y * image->width + x; + m[2]->r = image->data[0][ofs]; + m[2]->g = image->data[1][ofs]; + m[2]->b = image->data[2][ofs]; + + ofs = y * image->width + xx; + m[3]->r = image->data[0][ofs]; + m[3]->g = image->data[1][ofs]; + m[3]->b = image->data[2][ofs]; + + +/* + * m[0]->r=((m[0]->r*(256-dx)*(256-dy))+ + * (m[1]->r*dx*(256-dy))+ + * (m[2]->r*(256-dx)*dy)+ + * (m[3]->r*dx*dy))>>16; + * m[0]->g=((m[0]->g*(256-dx)*(256-dy))+ + * (m[1]->g*dx*(256-dy))+ + * (m[2]->g*(256-dx)*dy)+ + * (m[3]->g*dx*dy))>>16; + * m[0]->b=((m[0]->b*(256-dx)*(256-dy))+ + * (m[1]->b*dx*(256-dy))+ + * (m[2]->b*(256-dx)*dy)+ + * (m[3]->b*dx*dy))>>16; + */ + + if ((ofs = m[1]->r - m[0]->r) != 0) + m[0]->r += (ofs * dx) >> 8; + if ((ofs = m[1]->g - m[0]->g) != 0) + m[0]->g += (ofs * dx) >> 8; + if ((ofs = m[1]->b - m[0]->b) != 0) + m[0]->b += (ofs * dx) >> 8; + + if ((ofs = m[3]->r - m[2]->r) != 0) + m[2]->r += (ofs * dx) >> 8; + if ((ofs = m[3]->g - m[2]->g) != 0) + m[2]->g += (ofs * dx) >> 8; + if ((ofs = m[3]->b - m[2]->b) != 0) + m[2]->b += (ofs * dx) >> 8; + + if ((ofs = m[2]->r - m[0]->r) != 0) + m[0]->r += (ofs * dy) >> 8; + if ((ofs = m[2]->g - m[0]->g) != 0) + m[0]->g += (ofs * dy) >> 8; + if ((ofs = m[2]->b - m[0]->b) != 0) + m[0]->b += (ofs * dy) >> 8; + + return; +} +/* ------------------------------------------------------------------------ */ +void calcDistance() +{ + double tan_a; + + tan_a = (zoom * DIAMETRE / 2.0) / proj_dist; +/* + * distance of camera to center of earth ( = coordinate origin) + */ + center_dist = radius / sin(atan(tan_a)); + c_coef = center_dist * center_dist - radius * radius; + solution = FALSE; + return; +} +/* ------------------------------------------------------------------------ */ +void renderFrame() +{ + int py, px; + RColor teinte; + + double dir_x, dir_y, dir_z; /* direction of cast ray */ + + double hit_x, hit_y, hit_z; /* hit position on earth surface */ + + double hit2_x, hit2_y, hit2_z; /* mirrored hit position on earth surface */ + + double sp_x, sp_y, sp_z; /* intersection point of globe and ray */ + + double a; /* coeff. of quardatic equation */ + + double radikand; + double wurzel; + double r; /* r' */ + + double s1, s2, s; /*distance between intersections and + camera position */ + + double longitude, latitude; /* coordinates of hit position */ + + double light_angle; /* cosine of angle between sunlight and + surface normal */ + + int startx, endx; /* the region to be painted */ + + int starty, endy; + + double m11; + double m12; + double m13; + double m21; + double m22; + double m23; + double m31; + double m32; + double m33; + + a = dir_x = dir_y = 0; + dir_z = -proj_dist; + +#ifdef DEBUG + fprintf(stdout, "solution : %d\n", solution); +#endif + /* + * clear image + */ + if (solution == FALSE) + RClearImage(small, &noir); + + /* + * rotation matrix + */ + + m11 = cos(v_long); + m22 = cos(v_lat); + m23 = sin(v_lat); + m31 = -sin(v_long); + m12 = m23 * m31; + m13 = -m22 * m31; + m21 = 0.; + m32 = -m23 * m11; + m33 = m22 * m11; + + /* + * calc. radius of projected sphere + */ + if (solution == FALSE) { + b_coef = 2 * center_dist * dir_z; + radius_proj = (int) sqrt(b_coef * b_coef / (4 * c_coef) - dir_z * dir_z) + 1; + } +/*-----------------------------------------------------------------------------------------*/ + if (fun) { + starty = DIAMETRE / 2 - radius_proj - 3; + endy = DIAMETRE - starty - 1; + if ((double) starty < (double) (-funy)) + starty = -funy; + if ((double) starty > (double) (DIAMETRE - 1 - funy)) + starty = DIAMETRE - 1 - funy; + if ((double) endy < (double) (-funy)) + endy = -funy; + if ((double) endy > (double) (DIAMETRE - 1 - funy)) + endy = DIAMETRE - 1 - funy; + + for (py = starty; py <= endy; py++) { + + startx = DIAMETRE / 2 - 6 - + (int) sqrt(radius_proj * radius_proj - + (py - DIAMETRE / 2) * + (py - DIAMETRE / 2)); + + endx = DIAMETRE - startx - 1; + if ((double) startx < (double) (-funx)) + startx = -funx; + + if ((double) startx > (double) (DIAMETRE - 1 - funx)) + startx = DIAMETRE - 1 - funx; + + if ((double) endx < (double) (-funx)) + endx = -funx; + if ((double) endx > (double) (DIAMETRE - 1 - funx)) + endx = DIAMETRE - 1 - funx; + + /* + * calculate offset into image data + */ + + for (px = startx; px <= endx; px++) { + + dir_x = (double) px - DIAMETRE / 2 + 0.5; + dir_y = -(double) py + DIAMETRE / 2 - 0.5; + + a = dir_x * dir_x + dir_y * dir_y + dir_z * dir_z; + /* + * c constant, see above + */ + radikand = b_coef * b_coef - 4 * a * c_coef; /*what's under the sq.root when solving the + quadratic equation */ + + if (radikand >= 0.0) { /* solution exists <=> intersection */ + + wurzel = sqrt(radikand); + s1 = (-b_coef + wurzel) / (2. * a); + s2 = (-b_coef - wurzel) / (2. * a); + s = (s1 < s2) ? s1 : s2; /* smaller solution belongs to nearer + * intersection */ + + + sp_x = s * dir_x; /* sp = camera pos + s*dir */ + sp_y = s * dir_y; + sp_z = center_dist + s * dir_z; + + hit_x = m11 * sp_x + m12 * sp_y + m13 * sp_z; + hit_y = m22 * sp_y + m23 * sp_z; + hit_z = m31 * sp_x + m32 * sp_y + m33 * sp_z; + + hit2_x = -m11 * sp_x + m12 * sp_y + m13 * sp_z; + hit2_y = m22 * sp_y + m23 * sp_z; + hit2_z = -m31 * sp_x + m32 * sp_y + m33 * sp_z; +/*** hope hit_z wont get too close to zero *******/ + if (ABS(hit_z) < 0.001) { + if (hit_x * hit_z > 0.) + longitude = PI / 2.; + else + longitude = -PI / 2.; + if (hit_z > 0.) + hit_z = 0.001; + else + hit_z = -0.001; + } else { + longitude = atan(hit_x / hit_z); + } + + if (hit_z < 0.) + longitude += PI; + + r = (double) sqrt(hit_x * hit_x + hit_z * hit_z); + + latitude = atan(-hit_y / r); + + light_angle = + (light_x * hit_x + light_y * hit_y + light_z * hit_z) / radius; + + /* + * Set pixel in image + */ + + teinte = mygetMapColorLinear(longitude, latitude, light_angle); + RPutPixel(small, px + funx, py + funy, &teinte); + } + } /*px */ + } /*py */ + } +/*-----------------------------------------------------------------------------------------*/ +/*** not fun : ***/ + else { + starty = DIAMETRE / 2 - radius_proj - 3; + starty = (starty < 0) ? 0 : starty; + endy = DIAMETRE - starty - 1; +/* + * py 0 to 63 max + */ + for (py = starty; py <= endy; py++) { + startx = DIAMETRE / 2 - 6 - + (int) sqrt(radius_proj * radius_proj - + (py - DIAMETRE / 2) * + (py - DIAMETRE / 2)); + startx = (startx < 0) ? 0 : startx; +/* + * 0<= startx <=31 + */ + + for (px = startx; px < DIAMETRE / 2; px++) { + if (solution == FALSE) { + dir_x = (double) px - DIAMETRE / 2 + 0.5; + + dir_y = -(double) py + DIAMETRE / 2 - 0.5; + + a = dir_x * dir_x + dir_y * dir_y + dir_z * dir_z; + + + soluce[px][py][0] = b_coef * b_coef - 4 * a * c_coef; + /*what's under the sq.root when solving the + quadratic equation */ + + } + if (soluce[px][py][0] >= 0.0) { /* solution exists <=> intersection */ + + if (solution == FALSE) { + wurzel = sqrt(soluce[px][py][0]); + s1 = (-b_coef + wurzel) / (2. * a); + s2 = (-b_coef - wurzel) / (2. * a); + s = (s1 < s2) ? s1 : s2; /* smaller solution belongs to nearer + * intersection */ + + soluce[px][py][1] = s * dir_x; /* sp = camera pos + s*dir */ + soluce[px][py][2] = s * dir_y; + soluce[px][py][3] = center_dist + s * dir_z; + } + sp_x = soluce[px][py][1]; + sp_y = soluce[px][py][2]; + sp_z = soluce[px][py][3]; + hit_x = m11 * sp_x + m12 * sp_y + m13 * sp_z; + hit_y = m22 * sp_y + m23 * sp_z; + hit_z = m31 * sp_x + m32 * sp_y + m33 * sp_z; + + hit2_x = -m11 * sp_x + m12 * sp_y + m13 * sp_z; + hit2_y = m22 * sp_y + m23 * sp_z; + hit2_z = -m31 * sp_x + m32 * sp_y + m33 * sp_z; + +/*** hope hit_z wont get too close to zero *******/ +#ifdef DEBUG + if (ABS(hit_z) < ABS(minhz)) { + minhz = hit_z; + fprintf(stdout, "should >>0 : hit_z %f\n", hit_z); + fprintf(stdout, " hit_x %f\n", hit_x); + fprintf(stdout, " ratio %f\n", hit_x / hit_z); + fprintf(stdout, " long %f\n", atan(hit_x / hit_z)); + + sleep(5); + } +#endif + if (ABS(hit_z) < 0.001) { + if (hit_x * hit_z > 0.) + longitude = PI / 2.; + else + longitude = -PI / 2.; + if (hit_z > 0.) + hit_z = 0.001; + else + hit_z = -0.001; + } else { + longitude = atan(hit_x / hit_z); + } + + if (hit_z < 0.) + longitude += PI; + + r = (double) sqrt(hit_x * hit_x + hit_z * hit_z); + + latitude = atan(-hit_y / r); + + light_angle = + (light_x * hit_x + light_y * hit_y + light_z * hit_z) / radius; + if (sens == 1) { + + /* + * Set pixel in image + */ + + teinte = mygetMapColorLinear(longitude, latitude, light_angle); + myRPutPixel(px, py, &teinte); + + /* + * mirror the left half-circle of the globe: we need a new position + * and have to recalc. the light intensity + */ + + light_angle = + (light_x * hit2_x + light_y * hit2_y + light_z * hit2_z) / radius; + teinte = mygetMapColorLinear(2 * v_long - longitude, latitude, light_angle); + myRPutPixel(DIAMETRE - px - 1, py, &teinte); + } else { + /* sens==-1 */ + /* + * Set pixel in image + */ + + teinte = mygetMapColorLinear(longitude, latitude, light_angle); + myRPutPixel(DIAMETRE - px - 1, DIAMETRE - py - 1, &teinte); + + /* + * mirror the left half-circle of the globe: we need a new position + * and have to recalc. the light intensity + */ + + light_angle = + (light_x * hit2_x + light_y * hit2_y + light_z * hit2_z) / radius; + teinte = mygetMapColorLinear(2 * v_long - longitude, latitude, light_angle); + myRPutPixel(px, DIAMETRE - py - 1, &teinte); + } + } + } /*px */ + } /*py */ + } /*else fun */ + solution = TRUE; + return; +} +/*------------------------------------------------------------------------ */ +static RColor + mygetMapColorLinear(double longitude, double latitude, double angle) +{ + RColor point; + int x, y, xl, yl, dx, dy, ang; + + if (longitude < 0.) + longitude += 2 * PI; + + latitude += PI / 2; + + longitude += PI; + if (longitude >= 2 * PI) + longitude -= 2 * PI; + + if (angle > 0) + ang = (int) floor((1 - ((1 - angle) * dawn)) * 256); + else + ang = angle * 256; + + xl = (int) (longitude * mratiox); + yl = (int) (latitude * mratioy); + + x = xl >> 8; + y = yl >> 8; + dx = xl - (x << 8); + dy = yl - (y << 8); + + if (use_nightmap) { + if (ang > 0) { + getquarter(map, x, y, md, dx, dy); + getquarter(mapnight, x, y, mn, dx, dy); + + md[0]->r = ((mn[0]->r * (256 - ang) + md[0]->r * ang)) >> 8; + md[0]->g = ((mn[0]->g * (256 - ang) + md[0]->g * ang)) >> 8; + md[0]->b = ((mn[0]->b * (256 - ang) + md[0]->b * ang)) >> 8; + } else { + getquarter(mapnight, x, y, md, dx, dy); + } + } else { + getquarter(map, x, y, md, dx, dy); + if (ang > 0) { + md[0]->r = ((md[0]->r * aml + md[0]->r * ang / 256 * (256 - aml))) >> 8; + md[0]->g = ((md[0]->g * aml + md[0]->g * ang / 256 * (256 - aml))) >> 8; + md[0]->b = ((md[0]->b * aml + md[0]->b * ang / 256 * (256 - aml))) >> 8; + } else { + md[0]->r = (md[0]->r * aml) >> 8; + md[0]->g = (md[0]->g * aml) >> 8; + md[0]->b = (md[0]->b * aml) >> 8; + } + } + + point.red = (unsigned char) md[0]->r; + point.green = (unsigned char) md[0]->g; + point.blue = (unsigned char) md[0]->b; + point.alpha = 255; + return point; +} +/* ------------------------------------------------------------------------ */ +static void randomPosition() +{ + addlat = ((rand() % 30001) / 30000.) * 180. - 90.; + addlong = ((rand() % 30001) / 30000.) * 360. - 180.; + return; +} +/* ------------------------------------------------------------------------ */ +static void updateTime(int force) +{ +/* calcul of sun position every minute */ + if ((trend.tv_sec - tsunpos) >= 60 || force) { + tsunpos = trend.tv_sec; + GetSunPos(tsunpos, &sun_lat, &sun_long); + light_x = cos(sun_lat) * sin(sun_long); + light_y = sin(sun_lat); + light_z = cos(sun_lat) * cos(sun_long); + do_something = TRUE; + } + return; +} +/* ------------------------------------------------------------------------ */ +void setViewPos(double lat, double lon) +{ + double dif; + while (lat >= 360.) + lat -= 360.; + while (lat <= -360.) + lat += 360.; + while (addlat >= 360.) + addlat -= 360.; + while (addlat <= -360.) + addlat += 360.; + + if (lat >= 90.) { + dif = lat; + lat = 180. - lat; + addlat += (lat - dif); + dlat *= -1; + if (!fun) { + lon += 180.; + addlong += 180.; + } + sens *= -1; + } + if (lat <= -90.) { + dif = lat; + lat = -180. - lat; + addlat += (lat - dif); + dlat *= -1; + if (!fun) { + lon += 180.; + addlong += 180.; + } + sens *= -1; + } + if (lat >= 90.) { + dif = lat; + lat = 180. - lat; + addlat += (lat - dif); + dlat *= -1; + if (!fun) { + lon += 180.; + addlong += 180.; + } + sens *= -1; + } + if (lat <= -90.) { + dif = lat; + lat = -180. - lat; + addlat += (lat - dif); + dlat *= -1; + if (!fun) { + lon += 180.; + addlong += 180.; + } + sens *= -1; + } + while (lon >= 180.) { + lon -= 360.; + addlong -= 360.; + } + while (lon <= -180.) { + lon += 360.; + addlong += 360.; + } + + v_lat = lat * PI / 180.; + v_long = lon * PI / 180.; + dv_lat = lat; + dv_long = lon; + + return; +} +/* ------------------------------------------------------------------------ */ +void recalc(int calme) +{ + double coeff, va, vo; + struct timeval tv, tnow; + + tnow = getimev(); + trend = timeaccel(tnow); + tv = diftimev(tnow, tlast); + + if (firstTime) { + firstTime = FALSE; + updateTime(TRUE); + } else { + coeff = (double) tv.tv_sec + tv.tv_usec / 1000000.; + + if (!calme) { +/** while !clic button rotate earth **/ + addlat += dlat * coeff; + addlong += dlong * coeff; + } + } + + if (addlong != old_dvlong || addlat != old_dvlat || p_type == PTRANDOM) { + old_dvlong = addlong; + old_dvlat = addlat; + do_something = TRUE; + } + if (calme && p_type == PTSUNREL) { + va = sun_lat * 180. / PI; + vo = sun_long * 180. / PI; + updateTime(TRUE); + addlat -= sun_lat * 180. / PI - va; + addlong -= sun_long * 180. / PI - vo; + } else { + updateTime(FALSE); + } + + if (do_something) { + switch (p_type) { + case PTSUNREL: + setViewPos(sun_lat * 180. / PI + addlat, + sun_long * 180. / PI + addlong); + break; + + case PTFIXED: + setViewPos(addlat, addlong); + break; + + case PTRANDOM: + if (stoprand == FALSE) + randomPosition(); + else + stoprand--; + setViewPos(addlat, addlong); + break; + + default: + break; + } +#ifdef DEBUG + fprintf(stdout, "%s render\n", ctime(&trend.tv_sec)); +#endif + renderFrame(); + } + tlast = tnow; + tnext = addtimev(tnow, tdelay); + + return; +} +/* ------------------------------------------------------------------------ */ diff --git a/wmglobe/src/scrdiv.xpm b/wmglobe/src/scrdiv.xpm new file mode 100644 index 0000000..270cad5 --- /dev/null +++ b/wmglobe/src/scrdiv.xpm @@ -0,0 +1,73 @@ +/* XPM */ +static char * scrdiv_xpm[] = { +"64 64 6 1", +" c None", +". c #000000", +"+ c #CCCC6E", +"@ c #FFFFFF", +"# c #CCCCCC", +"$ c #F7F3FF", +" ", +"............................................................ ", +"....................................++...................... ", +"...................................+..+..................... ", +"...................................+..+..................... ", +"....................................++...................... ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +"............................................................ ", +" ", +"@@@@@@@@@@@@@@@@@@@#@@@@@@@$@@@$@@@@@@@#@@@@@@@@@@@@@@@@@@@# ", +"@#######.####.#####.@#####.####.#######.@##################. ", +"@######..###..#####.@#####..###..######.@##################. ", +"@#####...##...#####.@#####...##...#####.@#####.......######. ", +"@####....#....#####.@#####....#....####.@#####.......######. ", +"@#####...##...#####.@#####...##...#####.@#####.......######. ", +"@######..###..#####.@#####..###..######.@##################. ", +"@#######.####.#####.@#####.####.#######.@##################. ", +"#...................#...................#................... ", +" ", +"...................#...................#...................# ", +".#######.####.#####@.#####.####.#######@.##################@ ", +".######..###..#####@.#####..###..######@.##################@ ", +".#####...##...#####@.#####...##...#####@.#####.......######@ ", +".####....#....#####@.#####....#....####@.#####.......######@ ", +".#####...##...#####@.#####...##...#####@.#####.......######@ ", +".######..###..#####@.#####..###..######@.##################@ ", +".#######.####.#####@.#####.####.#######@.##################@ ", +"#@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@@ ", +" ", +".............................................................# ", +".@@@@@@@@@@@@@@@@@@@#@@@@@@@$@@@$@@@@@@@#@@@@@@@@@@@@@@@@@@@## ", +".@#######.####.#####.@#####.####.#######.@##################.# ", +".@######..###..#####.@#####..###..######.@##################.# ", +".@#####...##...#####.@#####...##...#####.@#####.......######.# ", +".@####....#....#####.@#####....#....####.@#####.......######.# ", +".@#####...##...#####.@#####...##...#####.@#####.......######.# ", +".@######..###..#####.@#####..###..######.@##################.# ", +".@#######.####.#####.@#####.####.#######.@##################.# ", +".#...................#...................#...................# ", +"############################################################## ", +" ", +" ", +" ", +" ", +" "}; diff --git a/wmglobe/src/scrpos.xpm b/wmglobe/src/scrpos.xpm new file mode 100644 index 0000000..1ca44fb --- /dev/null +++ b/wmglobe/src/scrpos.xpm @@ -0,0 +1,73 @@ +/* XPM */ +static char * scrpos_xpm[] = { +"64 64 6 1", +" c None", +". c #000000", +"+ c #CCCC6E", +"@ c #FFFFFF", +"# c #CCCCCC", +"$ c #F7F3FF", +" ", +" ", +" ", +" .. ... ...... ", +" .. ... ...... ", +" .. .. .. .. ", +" .. .. .. .. ", +" .. .. .. .. ", +" .. ....... .. ", +" ..... .. .. .. ", +" ..... .. .. .. ", +" ", +" ............................................................ ", +" ....................................++...................... ", +" ...................................+..+..................... ", +" ...................................+..+..................... ", +" ....................................++...................... ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ", +" ", +" .. ... .. .. .... ", +" .. .. .. ... .. .. .. ", +" .. .. .. ... .. .. . ", +" .. .. .. .. . .. .. ", +" .. .. .. .. . .. .. ... ", +" .. .. .. .. ... .. .. ", +" ..... .. .. .. ... .. .. ", +" ..... ... .. .. ... . ", +" ", +" ............................................................ ", +" ....................................++...................... ", +" ...................................+..+..................... ", +" ...................................+..+..................... ", +" ....................................++...................... ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ", +" ", +" ", +" @@@@@@@@@@@@@@@@@@@#@@@@@@@$@@@$@@@@@@@#@@@@@@@@@@@@@@@@@@@# ", +" @#######.####.#####.@#####.####.#######.@##################. ", +" @######..###..#####.@#####..###..######.@##################. ", +" @#####...##...#####.@#####...##...#####.@#####.......######. ", +" @####....#....#####.@#####....#....####.@#####.......######. ", +" @#####...##...#####.@#####...##...#####.@#####.......######. ", +" @######..###..#####.@#####..###..######.@##################. ", +" @#######.####.#####.@#####.####.#######.@##################. ", +" #...................#...................#................... ", +" ", +" ", +" "}; diff --git a/wmglobe/src/scrtime.xpm b/wmglobe/src/scrtime.xpm new file mode 100644 index 0000000..b15fa85 --- /dev/null +++ b/wmglobe/src/scrtime.xpm @@ -0,0 +1,72 @@ +/* XPM */ +static char * scrtime_xpm[] = { +"64 64 5 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #CCCCCC", +"# c #F7F3FF", +" ", +" ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ", +" ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ", +" ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ", +" ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ............................................................ ", +" ", +" ", +" ", +" ", +" +++++++++++++++++++@+++++++#+++#+++++++@+++++++++++++++++++@ ", +" +@@@@@@@.@@@@.@@@@@.+@@@@@.@@@@.@@@@@@@.+@@@@@@@@@@@@@@@@@@. ", +" +@@@@@@..@@@..@@@@@.+@@@@@..@@@..@@@@@@.+@@@@@@@@@@@@@@@@@@. ", +" +@@@@@...@@...@@@@@.+@@@@@...@@...@@@@@.+@@@@@.......@@@@@@. ", +" +@@@@....@....@@@@@.+@@@@@....@....@@@@.+@@@@@.......@@@@@@. ", +" +@@@@@...@@...@@@@@.+@@@@@...@@...@@@@@.+@@@@@.......@@@@@@. ", +" +@@@@@@..@@@..@@@@@.+@@@@@..@@@..@@@@@@.+@@@@@@@@@@@@@@@@@@. ", +" +@@@@@@@.@@@@.@@@@@.+@@@@@.@@@@.@@@@@@@.+@@@@@@@@@@@@@@@@@@. ", +" @...................@...................@................... ", +" ", +" ", +" "}; diff --git a/wmglobe/src/sunpos.c b/wmglobe/src/sunpos.c new file mode 100644 index 0000000..e46ee31 --- /dev/null +++ b/wmglobe/src/sunpos.c @@ -0,0 +1,278 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * sunpos.c is taken from Xearth : + */ +/* + * sunpos.c + * kirk johnson + * july 1993 + * + * code for calculating the position on the earth's surface for which + * the sun is directly overhead (adapted from _practical astronomy + * with your calculator, third edition_, peter duffett-smith, + * cambridge university press, 1988.) + * + * + * Copyright (C) 1989, 1990, 1993, 1994, 1995 Kirk Lauritz Johnson + * + * Parts of the source code (as marked) are: + * Copyright (C) 1989, 1990, 1991 by Jim Frost + * Copyright (C) 1992 by Jamie Zawinski + * + * Permission to use, copy, modify and freely distribute xearth for + * non-commercial and not-for-profit purposes is hereby granted + * without fee, provided that both the above copyright notice and this + * permission notice appear in all copies and in supporting + * documentation. + * + * Unisys Corporation holds worldwide patent rights on the Lempel Zev + * Welch (LZW) compression technique employed in the CompuServe GIF + * image file format as well as in other formats. Unisys has made it + * clear, however, that it does not require licensing or fees to be + * paid for freely distributed, non-commercial applications (such as + * xearth) that employ LZW/GIF technology. Those wishing further + * information about licensing the LZW patent should contact Unisys + * directly at (lzw_info@unisys.com) or by writing to + * + * Unisys Corporation + * Welch Licensing Department + * M/S-C1SW19 + * P.O. Box 500 + * Blue Bell, PA 19424 + * + * The author makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 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. + */ + +/*************************************************************************/ + +#include +#include + +#ifndef PI +#define PI 3.141592653 +#endif +#define TWOPI (2*PI) + +/* + * the epoch upon which these astronomical calculations are based is + * 1990 january 0.0, 631065600 seconds since the beginning of the + * "unix epoch" (00:00:00 GMT, Jan. 1, 1970) + * + * given a number of seconds since the start of the unix epoch, + * DaysSinceEpoch() computes the number of days since the start of the + * astronomical epoch (1990 january 0.0) + */ + +#define EpochStart (631065600) +#define DaysSinceEpoch(secs) (((secs)-EpochStart)*(1.0/(24*3600))) + +/* + * assuming the apparent orbit of the sun about the earth is circular, + * the rate at which the orbit progresses is given by RadsPerDay -- + * TWOPI radians per orbit divided by 365.242191 days per year: + */ + +#define RadsPerDay (TWOPI/365.242191) + +/* + * details of sun's apparent orbit at epoch 1990.0 (after + * duffett-smith, table 6, section 46) + * + * Epsilon_g (ecliptic longitude at epoch 1990.0) 279.403303 degrees + * OmegaBar_g (ecliptic longitude of perigee) 282.768422 degrees + * Eccentricity (eccentricity of orbit) 0.016713 + */ + +#define Epsilon_g (279.403303*(TWOPI/360)) +#define OmegaBar_g (282.768422*(TWOPI/360)) +#define Eccentricity (0.016713) + +/* + * MeanObliquity gives the mean obliquity of the earth's axis at epoch + * 1990.0 (computed as 23.440592 degrees according to the method given + * in duffett-smith, section 27) + */ +#define MeanObliquity (23.440592*(TWOPI/360)) + +/* + * solve Kepler's equation via Newton's method + * (after duffett-smith, section 47) + */ +static double solve_keplers_equation(double M) +{ + double E; + double delta; + + E = M; + while (1) { + delta = E - Eccentricity * sin(E) - M; + if (fabs(delta) <= 1e-10) + break; + E -= delta / (1 - Eccentricity * cos(E)); + } + + return E; +} + + +/* + * compute ecliptic longitude of sun (in radians) + * (after duffett-smith, section 47) + */ +static double sun_ecliptic_longitude(time_t ssue) + /* seconds since unix epoch */ +{ + double D, N; + double M_sun, E; + double v; + + D = DaysSinceEpoch(ssue); + + N = RadsPerDay * D; + N = fmod(N, TWOPI); + if (N < 0) + N += TWOPI; + + M_sun = N + Epsilon_g - OmegaBar_g; + if (M_sun < 0) + M_sun += TWOPI; + + E = solve_keplers_equation(M_sun); + v = 2 * atan(sqrt((1 + Eccentricity) / (1 - Eccentricity)) * tan(E / 2)); + + return (v + OmegaBar_g); +} + + +/* + * convert from ecliptic to equatorial coordinates + * (after duffett-smith, section 27) + */ +static void ecliptic_to_equatorial(double lambda, double beta, double *alpha, double *delta) +/* + * double lambda; ecliptic longitude + * double beta; ecliptic latitude + * double *alpha; (return) right ascension + * double *delta; (return) declination + */ +{ + double sin_e, cos_e; + + sin_e = sin(MeanObliquity); + cos_e = cos(MeanObliquity); + + *alpha = atan2(sin(lambda) * cos_e - tan(beta) * sin_e, cos(lambda)); + *delta = asin(sin(beta) * cos_e + cos(beta) * sin_e * sin(lambda)); +} + + +/* + * computing julian dates (assuming gregorian calendar, thus this is + * only valid for dates of 1582 oct 15 or later) + * (after duffett-smith, section 4) + */ +static double julian_date(int y, int m, int d) +/* + * int y; year (e.g. 19xx) + * int m; month (jan=1, feb=2, ...) + * int d; day of month + */ +{ + int A, B, C, D; + double JD; + + /* lazy test to ensure gregorian calendar */ +/* + * ASSERT(y >= 1583); + */ + + if ((m == 1) || (m == 2)) { + y -= 1; + m += 12; + } + A = y / 100; + B = 2 - A + (A / 4); + C = (int) (365.25 * y); + D = (int) (30.6001 * (m + 1)); + + JD = B + C + D + d + 1720994.5; + + return JD; +} + + +/* + * compute greenwich mean sidereal time (GST) corresponding to a given + * number of seconds since the unix epoch + * (after duffett-smith, section 12) + */ +static double GST(time_t ssue) + /*time_t ssue; seconds since unix epoch */ +{ + double JD; + double T, T0; + double UT; + struct tm *tm; + + tm = gmtime(&ssue); + + JD = julian_date(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + T = (JD - 2451545) / 36525; + + T0 = ((T + 2.5862e-5) * T + 2400.051336) * T + 6.697374558; + + T0 = fmod(T0, 24.0); + if (T0 < 0) + T0 += 24; + + UT = tm->tm_hour + (tm->tm_min + tm->tm_sec / 60.0) / 60.0; + + T0 += UT * 1.002737909; + T0 = fmod(T0, 24.0); + if (T0 < 0) + T0 += 24; + + return T0; +} + + +/* + * given a particular time (expressed in seconds since the unix + * epoch), compute position on the earth (lat, lon) such that sun is + * directly overhead. + */ +void GetSunPos(time_t ssue, double *lat, double *lon) +/* time_t ssue; seconds since unix epoch */ +/* double *lat; (return) latitude */ +/* double *lon; (return) longitude */ +{ + double lambda; + double alpha, delta; + double tmp; + + lambda = sun_ecliptic_longitude(ssue); + ecliptic_to_equatorial(lambda, 0.0, &alpha, &delta); + + tmp = alpha - (TWOPI / 24) * GST(ssue); + if (tmp < -PI) { + do + tmp += TWOPI; + while (tmp < -PI); + } else if (tmp > PI) { + do + tmp -= TWOPI; + while (tmp < -PI); + } + *lon = tmp; + *lat = delta; +} diff --git a/wmglobe/src/wmglobe.c b/wmglobe/src/wmglobe.c new file mode 100644 index 0000000..b59eefd --- /dev/null +++ b/wmglobe/src/wmglobe.c @@ -0,0 +1,387 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************/ +/* + * I used many functions of wmgeneral.c ("openXwindow") + * for the main function of wmglobe.c + * wmgeneral.c was taken from wmaker applet wmtune-1.0 : + * Author: Martijn Pieterse (pieterse@xs4all.nl) + * + * wmglobe.c uses functions of : Xglobe, Xearth, wmgeneral, wmaker/wrlib + ***************************************************************************/ + +#include "wmglobe.h" + +#include "cadre0.xbm" +#include "cadre1.xbm" +#include "cadre2.xbm" + +#ifdef DEFMAPOK +#include "defmap.xpm" +#include "defnimap.xpm" +#endif + +/***************************************************************************/ + +int main(int argc, char *argv[]) +{ + unsigned int borderwidth = 1; + XClassHint classHint; + char *wname = argv[0]; + XTextProperty name; + + XGCValues gcv; + unsigned long gcm; + XWindowAttributes attributes; + XColor color; + + RContext *ctx; + + XSizeHints mysizehints; + XWMHints mywmhints; + Pixel back_pix, fore_pix; + char Geometry[256]; + + char *rond_bits; + + int dummy = 0; + int ok, redoaction, wait_release, move_lat_flag; + int xx, yy; + +/** initialisation *********************/ + + xx = 0; + yy = 0; + ok = FALSE; + move_lat_flag = FALSE; + redoaction = 0; + wait_release = 0; + + setlocale(LC_TIME, ""); + +#ifdef DEBUG + fprintf(stdout, "%s\n", setlocale(LC_TIME, "")); +#endif + + set_defaults(); + + cmdline(argc, argv); + + switch (typecadre) { + case 1: + rond_bits = cadre1_bits; + break; + case 2: + rond_bits = cadre2_bits; + break; + default: + rond_bits = cadre0_bits; + } + if (p_type == PTRANDOM) { + dlat = 0; + dlong = 0; + } + initmyconvert(); + + tdelay.tv_sec = (int) floor(delay); + tdelay.tv_usec = (int) ((delay - tdelay.tv_sec) * 1000000); + aml = (int) floor(ambient_light * 256); + +/****************************************************************************/ + + if (!(dpy = XOpenDisplay(dpy_name))) { + fprintf(stderr, "%s: can't open display \"%s\"\n", + wname, XDisplayName(dpy_name)); + exit(1); + } + ctx = myRCreateContext(dpy, DefaultScreen(dpy), NULL); + + if (ctx->attribs->use_shared_memory) { +#ifdef DEBUG + fprintf(stdout, "enleve les flags use_shared_memory\n"); +#endif + ctx->attribs->flags ^= RC_UseSharedMemory; + ctx->attribs->use_shared_memory = FALSE; + ctx->flags.use_shared_pixmap = 0; + } +#ifdef DEBUG + fprintf(stdout, "depth %d\n", ctx->depth); + fflush(stdout); +#endif + +/* + * loading maps ............. + * + */ + + if (dayfile != NULL) { + map = RLoadImage(ctx, dayfile, 0); + if (!map) { + fprintf(stdout, "pb map ! file not found ?\n"); + exit(1); + } + } else { +#ifdef DEFMAPOK + map = RGetImageFromXPMData(ctx, defmap_xpm); + if (!map) { + fprintf(stdout, "pb def map ! file not found ?\n"); + exit(1); + } + nightfile = NULL; + use_nightmap = TRUE; + } +#else + fprintf(stdout, "need a map !\n"); + exit(1); + } +#endif + + if (use_nightmap) { + if (nightfile != NULL) { + mapnight = RLoadImage(ctx, nightfile, 0); + if (!mapnight) { + fprintf(stdout, "pb map night! file not found ?\n"); + exit(1); + } + } else { +#ifdef DEFMAPOK + mapnight = RGetImageFromXPMData(ctx, defnimap_xpm); + if (!mapnight) { + fprintf(stdout, "pb def map night ! file not found ?\n"); + exit(1); + } + } +#else +/* not very useful... */ + use_nightmap = FALSE; + } +#endif + } + use_nmap_ini = use_nightmap; + if (!oknimap) + use_nightmap = FALSE; +/* some other init ..................................... */ + ratiox = (double) map->width / (2 * PI); + ratioy = (double) map->height / PI; + mratiox = (int) floor(ratiox * 256); + mratioy = (int) floor(ratioy * 256); + loadxpm(ctx->drawable); + + small = RCreateImage(DIAMETRE, DIAMETRE, 1); + + calcDistance(); +/*...................................................... */ + +/* + * first rendering of the earth + */ + recalc(0); + do_something = FALSE; + + +/************************************************************************* + * well, here the problems begin : this code is a merge from wmgeneral and + * some stuff of wmaker, should be rewritten ... + ************************************************************************/ + + /* wmg */ + + XGetWindowAttributes(dpy, ctx->drawable, &attributes); + + if (!RConvertImage(ctx, small, &pix)) { + fprintf(stdout, "error small->&pix\n"); + puts(RMessageForError(RErrorCode)); + exit(1); + } + wmg.pixmap = pix; + wmg.mask = pix; + + mysizehints.flags = USSize | USPosition; + mysizehints.x = 0; + mysizehints.y = 0; + + color.pixel = 0; + if (!XParseColor(dpy, attributes.colormap, "white", &color)) { + fprintf(stdout, "wmglobe: can't parse white\n"); + } else if (!XAllocColor(dpy, attributes.colormap, &color)) { + fprintf(stdout, "wmglobe: can't allocate white\n"); + } + back_pix = color.pixel; + + XGetWindowAttributes(dpy, ctx->drawable, &attributes); + + color.pixel = 0; + if (!XParseColor(dpy, attributes.colormap, "black", &color)) { + fprintf(stdout, "wmglobe: can't parse black\n"); + } else if (!XAllocColor(dpy, attributes.colormap, &color)) { + fprintf(stdout, "wmglobe: can't allocate black\n"); + } + fore_pix = color.pixel; + + + XWMGeometry(dpy, ctx->screen_number, Geometry, NULL, borderwidth, &mysizehints, + &mysizehints.x, &mysizehints.y, &mysizehints.width, &mysizehints.height, &dummy); + mysizehints.width = DIAMETRE; + mysizehints.height = DIAMETRE; + + win = XCreateSimpleWindow(dpy, ctx->drawable, mysizehints.x, mysizehints.y, + mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix); + + iconwin = XCreateSimpleWindow(dpy, win, mysizehints.x, mysizehints.y, + mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix); + + /* Activate hints */ + XSetWMNormalHints(dpy, win, &mysizehints); + classHint.res_name = wname; + classHint.res_class = wname; + XSetClassHint(dpy, win, &classHint); + + XSelectInput(dpy, win, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask); + XSelectInput(dpy, iconwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask); + + if (XStringListToTextProperty(&wname, 1, &name) == 0) { + fprintf(stdout, "%s: can't allocate window name\n", wname); + exit(1); + } + XSetWMName(dpy, win, &name); + + /* Create GC for drawing */ + + gcm = GCForeground | GCBackground | GCGraphicsExposures; + gcv.foreground = fore_pix; + gcv.background = back_pix; + gcv.graphics_exposures = 0; + NormalGC = XCreateGC(dpy, ctx->drawable, gcm, &gcv); + + /* ONLYSHAPE ON */ + if (onlyshape) { + pixmask = XCreateBitmapFromData(dpy, win, rond_bits, DIAMETRE, DIAMETRE); + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pixmask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet); + } + /* ONLYSHAPE OFF */ + + mywmhints.initial_state = option_iw; + mywmhints.icon_window = iconwin; + mywmhints.icon_x = mysizehints.x; + mywmhints.icon_y = mysizehints.y; + mywmhints.window_group = win; + mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; + + XSetWMHints(dpy, win, &mywmhints); + + XSetCommand(dpy, win, argv, argc); + XMapWindow(dpy, win); + +/****************************************************************************/ + + + XCopyArea(dpy, wmg.pixmap, win, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + + + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + +/* + * ================= MAIN LOOP ================== + */ + while (1) { + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: +/* + * earth rotate when clic left (1) , zooming when middle (2) + * change screen to longitude / latitude when (3) + */ + switch (Event.xbutton.button) { + case 1: +#ifdef MOUSE_LAT_NO_SHIFT + move_lat_flag = TRUE; +#else + if (Event.xbutton.state & ShiftMask) + move_lat_flag = TRUE; + else + move_lat_flag = FALSE; +#endif + redoaction = 1; + wait_release = 1; + break; + case 2: + if (Event.xbutton.state & ShiftMask) + redoaction = 2; + else + redoaction = 3; + wait_release = 1; + break; + case 3: + wait_release = 0; + redoaction = 0; + screen_back(); + ok = TRUE; + break; + default: + break; + } + break; + case ButtonRelease: + wait_release = 0; + redoaction = 0; + break; + default: + break; + } + } + if (wait_release) { + usleep(2 * VAL_USLEEP_SHORT); + if (redoaction == 1) + rotation_terre(Event.xbutton.x, Event.xbutton.y, move_lat_flag); + else + zooming(Event.xbutton.state & ShiftMask); + ok = TRUE; + } + if (diftimev(tnext, getimev()).tv_sec < 0 || ok) { + ok = FALSE; + recalc(redoaction == 1); + if (do_something) { + if (!myRConvertImage(ctx, small, &pix)) { + fprintf(stdout, "plante !?\n"); + fprintf(stdout, RMessageForError(RErrorCode)); + exit(1); + } + wmg.pixmap = pix; + wmg.mask = pix; + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); +#ifdef DEBUG + fprintf(stdout, "draw\n"); +#endif + do_something = FALSE; + } + } + usleep(VAL_USLEEP); + } +/* + * Still wonder about freeing some memory for X + */ + return 0; +} diff --git a/wmglobe/src/wmglobe.h b/wmglobe/src/wmglobe.h new file mode 100644 index 0000000..9456f00 --- /dev/null +++ b/wmglobe/src/wmglobe.h @@ -0,0 +1,197 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************/ +/* it uses some functions of : Xglobe, Xearth, wmgeneral, wmaker/wrlib + ***************************************************************************/ + + +#ifndef WMG_HEADER_H +#define WMG_HEADER_H + +/* customization : see wmgoption.h */ + +#include +#include +#include +#include +#include +#include +#include +#include /*toupper */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wraster.h" + +#include "wmgoption.h" + +#define FALSE 0 +#define TRUE 1 +#define MAX(x, y) ((x) < (y) ? (y) : (x)) +#define MIN(x, y) ((x) > (y) ? (y) : (x)) +#define ABS(a) ((a) < 0 ? -(a) : (a)) + +#define PTFIXED 1 +#define PTSUNREL 2 +#define PTRANDOM 3 + +#ifndef PI +#define PI 3.141592653 +#endif + +/* + * wmglobe + * variables globales + */ + +/************/ +/* Typedefs */ +/************/ +#define MAX_MOUSE_REGION (8) + +typedef struct { + int enable; + int top; + int bottom; + int left; + int right; +} MOUSE_REGION; + +MOUSE_REGION mouse_region[MAX_MOUSE_REGION]; + +typedef struct MPO { + int r, g, b; +} MPO; + +MPO *md[4], *mn[4]; + +double soluce[DIAMETRE / 2][DIAMETRE][4]; +int solution; + +/************/ + +typedef struct { + Pixmap pixmap; + Pixmap mask; + XpmAttributes attributes; +} XpmIcon; + +/************/ + + +Display *dpy; + +char *dayfile, *nightfile, *dpy_name; + +Pixmap pix, pixmask; + +XEvent Event; + +RImage *map, *small, *mapnight; + +XpmIcon screenpos, scrdate, scrdiv, numpix, txtpix, wmg; + +Window iconwin, win; +int onlyshape, option_iw; +GC NormalGC; + +/********* rendering********/ + +double delay, time_multi; +/* + * struct timeval delta_tim, last_tim, next_tim, render_tim, base_tim, + * vec_tim; + * + * time_t beg_time, ini_time,t1901; + */ +struct timeval tlast, tnext, trend, tdelay, tini, tbase; +time_t tsunpos; + +int sens, fun, funx, funy, oknimap, mratiox, mratioy, gotoscr; + +int typecadre, p_type, use_nightmap, use_nmap_ini, firstTime, stoprand, + do_something, iop; + +double v_lat, v_long, old_dvlat, old_dvlong, dv_lat, dv_long; +double dlat, dlong, addlat, addlong, ratiox, ratioy, dawn; + +double sun_lat; +double sun_long; + +double fov; +double radius; +double proj_dist; /* distance to projection plane */ + +double center_dist; /* distance to center of earth */ + +double ambient_light; /* how dark is the dark side? */ + +double light_x, light_y, light_z; /* vector of sunlight with lengt 1 */ + +double c_coef, b_coef; +double zoom; +int radius_proj, aml; /* radius of sphere on screen */ + +RColor noir; +#ifdef DEBUG +double minhz; +#endif + +/****************************************************************/ +/* Function Prototypes */ +/****************************************************************/ +int main(int argc, char *argv[]); +/****************************************************************/ +void AddMouseRegion(int index, int left, int top, int right, int bottom); +int CheckMouseRegion(int x, int y); +void RedrawWindowXYWH(int x, int y, int w, int h); +void set_defaults(); +void loadxpm(Window drawable); +void cmdline(int argc, char *argv[]); +void screen_back(); +void rotation_terre(int x, int y, int lat_flag); +void zooming(int facto); +struct timeval diftimev(struct timeval t1, struct timeval t2); +struct timeval addtimev(struct timeval t1, struct timeval t2); +struct timeval getimev(); + +/***************************************************************/ +void setZoom(double z); +void calcDistance(); +void renderFrame(); +void initmyconvert(); +int myRConvertImage(RContext * context, RImage * image, Pixmap * pixmap); +RContext *myRCreateContext + (Display * dpy, int screen_number, RContextAttributes * attribs); +void setTime(struct timeval t); +void recalc(int calme); +void GetSunPos(time_t ssue, double *lat, double *lon); +void setViewPos(double lat, double lon); + +/***************************************************************/ + +#endif diff --git a/wmglobe/src/wmgoption.h b/wmglobe/src/wmgoption.h new file mode 100644 index 0000000..35d86b4 --- /dev/null +++ b/wmglobe/src/wmgoption.h @@ -0,0 +1,87 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************/ + +/* + * #define DEBUG + */ + +#define WMGVERSION "WMGlobe v.0.5 6 fev 1999 " + +/* + * comment DEFMAPOK to not install the built-in default maps, + * (smaller binary) usefull if you never use the default map + */ + +#define DEFMAPOK + +/* + * uncomment MOUSE_LAT_FULL to supprim the shift+left method of rotate earth + */ + +/* + * #define MOUSE_LAT_NO_SHIFT + */ + +/* + * number of parameter screen : min 1, max 7 (all, the recommanded default) + * - this doesnt modify the binary size - + * 1 : postion latitude & longitude + * 2 : time of viewpoint (+ screen 1) + * 3 : delay & zoom (+ screen 1 & 2) + * 4 : light & dawn (+ screen 1..3) + * 5 : accel & night map (+ screen 1..4) + * 6 : dlat & dlong (+ screen 1..5) + * 7 : type of view (+ screen 1..6) + */ +#define NUM_SCREEN 7 + +/*** 0.04 sec main loop sleep (maximum refresh rate when delay=0) ***/ +#define VAL_USLEEP 40000 + +#define VAL_USLEEP_SHORT 500 + +/* waiting time before get back from param screen to earth (seconds) */ +#define SCREEN_WAIT 5 + +#define ZOOM_FACTOR 1.06 +#define ZOOM_MIN 0.08 +#define ZOOM_MAX 100000.0 +#define STOP_RANDOM_FACTOR 1 +#define RATIO_ROTATE 0.5 + + +#define DEFAULT_DELAY 1.0 +#define DEFAULT_V_LAT 0.0 +#define DEFAULT_V_LONG 0.0 +#define DEFAULT_SENS 1 +#define DEFAULT_ZOOM 1.0 +#define DEFAULT_LIGHT 0.25 +#define DEFAULT_BORDER 0 +#define DEFAULT_NIGHTMAP 1 /* 1 or 0 */ + +#define MAX_DELAY_SEC 86400.0 +#define MAX_MULTI_COEF 864000.0 +#define MAX_DELTA_LONG 1800.0 + +/*** (1 - dawn/2) *****/ +#define DEFAULT_DAWN 0.9 + +/* change this if not 64x64 icons (not deep tested) you will need to change + the cadrex.xbm too and a few other things for the parameters menus + --- DIAMETRE must be a multiple of 2 --- */ +#define DIAMETRE 64 diff --git a/wmglobe/src/wmgutil.c b/wmglobe/src/wmgutil.c new file mode 100644 index 0000000..8b35888 --- /dev/null +++ b/wmglobe/src/wmgutil.c @@ -0,0 +1,2357 @@ +/* WMGlobe 0.5 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************/ +/* + * I used many functions of wmgeneral.c ("openXwindow") + * for the main function of wmglobe.c + * wmgeneral.c was taken from wmaker applet wmtune-1.0 : + * Author: Martijn Pieterse (pieterse@xs4all.nl) + * + * wmglobe.c uses functions of : Xglobe, Xearth, wmgeneral, wmaker/wrlib + ***************************************************************************/ + +#include "wmglobe.h" +#include "zapnum.xpm" +#include "zaptxt.xpm" +#include "zapnum.h" +#include "scrpos.xpm" +#include "scrtime.xpm" +#include "scrdiv.xpm" + +static void move_earth(double vla, double vlo); +static int flush_expose(Window w); +static void mqparam(); +static double getdegre(char *val); +static void screen_1(); +static void screen_2(); +static void screen_3(); +static void screen_4(); +static void screen_5(); +static void screen_6(); +static void screen_7(); +static void write_icon(char *txt, int x, int y); +static void chiffre(int ch, int xx, int yy); +static int lettre(char c, int xx, int yy); +static void display_pos(double la, double lo); +static void display_date(double la, double lo); +static void release_but(int ckm); +static void press_but(int ckm); +static void display_zoom(); +static void display_light(); +static void display_accel(); +static void display_dlat(); +static void display_type(); +static void move_delay(int factor); +static void move_zoom(int factor); +static void move_light(int factor); +static void move_dawn(int factor); +static void move_accel(int factor); +static void move_dlat(int factor); +static void move_dlong(int factor); +/* ------------------------------------------------------------------------ */ +/* + * TIME FUNCTIONS + */ +/* ------------------------------------------------------------------------ */ +struct timeval diftimev(struct timeval t1, struct timeval t2) +{ + t1.tv_usec -= t2.tv_usec; + if (t1.tv_usec < 0) { + t1.tv_usec += 1000000; + t1.tv_sec--; + } + t1.tv_sec -= t2.tv_sec; + return t1; +} +/* ------------------------------------------------------------------------ */ +struct timeval addtimev(struct timeval t1, struct timeval t2) +{ + t1.tv_usec += t2.tv_usec; + if (t1.tv_usec >= 1000000) { + t1.tv_usec -= 1000000; + t1.tv_sec++; + } + t1.tv_sec += t2.tv_sec; + return t1; +} +/* ------------------------------------------------------------------------ */ +struct timeval getimev() +{ + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + return tv; +} +/* ------------------------------------------------------------------------ */ +/* + * INIT FUNCTIONS + * + * defaults, commandline + * init of pixmap for screenpos and numbers displaying + */ +/* ------------------------------------------------------------------------ */ +void loadxpm(Window draw) +{ + XpmCreatePixmapFromData(dpy, draw, scrpos_xpm, &(screenpos.pixmap), + &(screenpos.mask), &(screenpos.attributes)); + XpmCreatePixmapFromData(dpy, draw, scrtime_xpm, &(scrdate.pixmap), + &(scrdate.mask), &(scrdate.attributes)); + XpmCreatePixmapFromData(dpy, draw, zapnum_xpm, &(numpix.pixmap), + &(numpix.mask), &(numpix.attributes)); + XpmCreatePixmapFromData(dpy, draw, zaptxt_xpm, &(txtpix.pixmap), + &(txtpix.mask), &(txtpix.attributes)); + XpmCreatePixmapFromData(dpy, draw, scrdiv_xpm, &(scrdiv.pixmap), + &(scrdiv.mask), &(scrdiv.attributes)); + return; +} +/* ------------------------------------------------------------------------ */ +void set_defaults() +{ + firstTime = TRUE; + dayfile = NULL; + use_nightmap = FALSE; + nightfile = NULL; + oknimap = DEFAULT_NIGHTMAP; + p_type = PTSUNREL; + delay = DEFAULT_DELAY; + tini = getimev(); + tbase = tini; + tsunpos = 0; + tlast.tv_sec = 0; + tlast.tv_usec = 0; + do_something = TRUE; + time_multi = 1.0; + v_lat = DEFAULT_V_LAT / 180. * PI; + v_long = DEFAULT_V_LONG / 180. * PI; + dv_lat = DEFAULT_V_LAT; + dv_long = DEFAULT_V_LONG; + old_dvlat = DEFAULT_V_LAT; + old_dvlong = DEFAULT_V_LONG; + iop = 0; + dlat = 0.0; + dlong = 0.0; + addlat = 0.0; + addlong = 0.0; + radius = 1000.0; + sun_long = 0.0; + sun_lat = 0.0; + fov = 0.5 * PI / 180.; + sens = DEFAULT_SENS; + zoom = DEFAULT_ZOOM; + ambient_light = DEFAULT_LIGHT; + dawn = DEFAULT_DAWN; + typecadre = DEFAULT_BORDER; + fun = FALSE; + funx = 0; + funy = 0; + dpy_name = NULL; + onlyshape = TRUE; + option_iw = WithdrawnState; + stoprand = FALSE; + solution = FALSE; + proj_dist = DIAMETRE / tan(fov); + noir.red = 0; + noir.green = 0; + noir.blue = 0; + noir.alpha = 255; + + md[0] = (MPO *) malloc(sizeof(MPO)); + md[1] = (MPO *) malloc(sizeof(MPO)); + md[2] = (MPO *) malloc(sizeof(MPO)); + md[3] = (MPO *) malloc(sizeof(MPO)); + mn[0] = (MPO *) malloc(sizeof(MPO)); + mn[1] = (MPO *) malloc(sizeof(MPO)); + mn[2] = (MPO *) malloc(sizeof(MPO)); + mn[3] = (MPO *) malloc(sizeof(MPO)); +#ifdef DEBUG + minhz = 1.; +#endif + return; +} +/* ------------------------------------------------------------------------ */ +static double getdegre(char *val) +{ + double d, m, s; + if (strchr(val, '°') != NULL || strchr(val, 'd') != NULL + || strchr(val, 'D') != NULL || strchr(val, ':') != NULL) { + d = m = s = 0; + sscanf(val, "%lf%*c%lf%*c%lf", &d, &m, &s); + if (d >= 0.) + return d + m / 60. + s / 3600.; + else + return d - m / 60. - s / 3600.; + } else { + return atof(val); + } +} +/* ------------------------------------------------------------------------ */ +static void mqparam() +{ + printf("error in parameters\n"); + exit(1); +} + +/* ------------------------------------------------------------------------ */ +void cmdline(int argc, char *argv[]) +{ + int i, j; + + if (argc > 0) { + for (i = 1; i < argc; i++) { + j = 0; + +/* ---------------------------------------------------- */ + if (strcasecmp(argv[i], "-v") == 0 + || strcasecmp(argv[i], "-version") == 0) { + printf("%s\n", WMGVERSION); + exit(0); + } +/* ---------------------------------------------------- */ + if (strcasecmp(argv[i], "-w") == 0 + || strcasecmp(argv[i], "-wmaker") == 0) { + option_iw = WithdrawnState; + j = 1; + } +/* ---------------------------------------------------- */ + if (strcasecmp(argv[i], "-i") == 0 + || strcasecmp(argv[i], "-iconic") == 0) { + option_iw = IconicState; + j = 1; + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-s") == 0 || + strcasecmp(argv[i], "-shape") == 0)) { + onlyshape = TRUE; + j = 1; + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-d") == 0 + || strcasecmp(argv[i], "-display") == 0)) { + i++; + if (i < argc) { + j = 1; + dpy_name = argv[i]; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-rand") == 0 + || strcasecmp(argv[i], "-random") == 0)) { + p_type = PTRANDOM; + srandom(((int) time(NULL)) + ((int) getpid())); + j = 1; + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-oz") == 0 + || strcasecmp(argv[i], "-austral") == 0)) { + sens = -1; + j = 1; + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-map") == 0) { + + i++; + if (i < argc) { + j = 1; + free(dayfile); + if ((dayfile = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { + fprintf(stderr, "erreur memoire options map\n"); + exit(1); + }; + strcpy(dayfile, argv[i]); + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-nimap") == 0 + || strcasecmp(argv[i], "-nightmap") == 0 + || strcasecmp(argv[i], "-night") == 0)) { + + i++; + if (i < argc) { + j = 1; + free(nightfile); + if ((nightfile = (char *) malloc(strlen(argv[i]) + 1)) == NULL) { + fprintf(stderr, "erreur memoire options nimap\n"); + exit(1); + }; + strcpy(nightfile, argv[i]); + use_nightmap = TRUE; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-accel") == 0 + || strcasecmp(argv[i], "-accell") == 0 + || strcasecmp(argv[i], "-acc") == 0 + || strcasecmp(argv[i], "-multi") == 0)) { + i++; + if (i < argc) { + j = 1; + time_multi = atof(argv[i]); + if (time_multi < 1.0) + time_multi = 1.0; + if (time_multi > MAX_MULTI_COEF) + time_multi = MAX_MULTI_COEF; + if (time_multi > 24.0) + time_multi = floor(time_multi); + else + time_multi = floor(time_multi * 10.0) / 10.0; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-nonimap") == 0 + || strcasecmp(argv[i], "-nonightmap") == 0 + || strcasecmp(argv[i], "-nonight") == 0 + || strcasecmp(argv[i], "-nomap") == 0)) { + j = 1; + use_nightmap = FALSE; + oknimap = FALSE; + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-zoom") == 0) { + i++; + if (i < argc) { + j = 1; + zoom = atof(argv[i]); + if (zoom < ZOOM_MIN) + zoom = ZOOM_MIN; + if (zoom > ZOOM_MAX) + zoom = ZOOM_MAX; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-dawn") == 0) { + i++; + if (i < argc) { + j = 1; + dawn = atof(argv[i]); + dawn = MAX(0.0, dawn); + dawn = MIN(1.0, dawn); + + dawn = (1.0 - dawn / 2.0); + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-delay") == 0) { + i++; + if (i < argc) { + j = 1; + delay = atof(argv[i]); + if (delay < 0) + delay = 0; + if (delay > MAX_DELAY_SEC) + delay = MAX_DELAY_SEC; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-dlat") == 0 + || strcasecmp(argv[i], "-lat") == 0 + || strcasecmp(argv[i], "-dlatitude") == 0)) { + i++; + if (i < argc) { + j = 1; + dlat = getdegre(argv[i]); + if (dlat < -MAX_DELTA_LONG) + dlat = -MAX_DELTA_LONG; + if (dlat > MAX_DELTA_LONG) + dlat = MAX_DELTA_LONG; + p_type = PTFIXED; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-dlong") == 0 + || strcasecmp(argv[i], "-long") == 0 + || strcasecmp(argv[i], "-dlongitude") == 0)) { + i++; + if (i < argc) { + j = 1; + dlong = getdegre(argv[i]); + if (dlong < -MAX_DELTA_LONG) + dlong = -MAX_DELTA_LONG; + if (dlong > MAX_DELTA_LONG) + dlong = MAX_DELTA_LONG; + p_type = PTFIXED; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-light") == 0) { + i++; + if (i < argc) { + j = 1; + ambient_light = atof(argv[i]); + if (ambient_light < 0.) + ambient_light = 0.; + if (ambient_light > 1.) + ambient_light = 1.; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-time") == 0) { + i++; + if (i < argc) { + j = 1; + tbase.tv_sec = atoi(argv[i]); + tbase.tv_usec = 0; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-bord") == 0 + || strcasecmp(argv[i], "-border") == 0)) { + i++; + if (i < argc) { + j = 1; + typecadre = atoi(argv[i]); + if (typecadre < 0) + typecadre = 0; + if (typecadre > 2) + typecadre = 2; + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && strcasecmp(argv[i], "-fun") == 0) { + fun = TRUE; + i++; + if (i < argc) { + funx = atoi(argv[i]); + + i++; + if (i < argc) { + j = 1; + funy = atoi(argv[i]); + } else { + mqparam(); + i--; + } + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + if (!j && (strcasecmp(argv[i], "-pos") == 0 + || strcasecmp(argv[i], "-position") == 0 + || strcasecmp(argv[i], "-fixed") == 0)) { + p_type = PTFIXED; + i++; + if (i < argc) { + addlat = getdegre(argv[i]); + i++; + if (i < argc) { + j = 1; + addlong = getdegre(argv[i]); + } else { + mqparam(); + i--; + } + } else { + mqparam(); + i--; + } + } +/* ---------------------------------------------------- */ + + if (!j && argv[i][0] == '-') { + printf("%s\n", WMGVERSION); + printf("\n"); + printf("-v : version -h : this help message !\n"); + printf("-zoom zoom_value : changing apparent size in icon\n"); + printf("-pos latitude long. : fixed initial position (default=follow sun)\n"); + printf("-rand : random position at every refresh\n"); + printf("-map map_file : use this map for rendering\n"); + printf("-nimap night_file : and this one for the dark side of earth\n"); + printf("-nonimap : don't use the default night map\n"); + printf("-delay seconds : time between refresh of image\n"); + printf("-dlat delta_lat : latitude speed of point of view (default=follow sun)\n"); + printf("-dlong delta_long : the same for longitude\n"); + printf("-light light_value : level of light for dark side of earth\n"); + printf("-dawn dawn_value : level of continuity for dawn limit\n"); + printf("-bord border_num : 0 1 or 2 , type of icon border.\n"); + printf("-accel time_multi : time accelerator\n"); + printf("-time seconds : time to display in seconds since 01-01-1970\n"); + printf("-oz : start in \"austral\" mode (for \"down under\" people)\n"); + printf("-fun dx dy : offset of vision... almost useless\n"); + printf("-w -shape : set by default (WMaker dockable application)\n"); + printf("-d display : display (WindowMaker not needed on the server side)\n"); + printf("left button : change longitude, with shift key, change latitude too\n"); + printf("middle button : zoom in, shift + middle button : zoom out\n"); + printf("right button : access to a few screens of parameters\n"); + exit(0); + } +/* ------------------------------------------------------------------------ */ + } + } + return; +} + +/**************************************************************************** + * X functions, mouse selection + * + */ + +/* ------------------------------------------------------------------------ */ +static int flush_expose(Window w) +{ + XEvent dummy; + int i = 0; + + while (XCheckTypedWindowEvent(dpy, w, Expose, &dummy)) + i++; + return i; +} +/* ------------------------------------------------------------------------ */ +void RedrawWindowXYWH(int x, int y, int w, int h) +{ + flush_expose(iconwin); + XCopyArea(dpy, wmg.pixmap, iconwin, NormalGC, x, y, w, h, x, y); + flush_expose(win); + XCopyArea(dpy, wmg.pixmap, win, NormalGC, x, y, w, h, x, y); + return; +} +/* ------------------------------------------------------------------------ */ +void AddMouseRegion(int index, int left, int top, int right, int bottom) +{ + if (index < MAX_MOUSE_REGION) { + mouse_region[index].enable = 1; + mouse_region[index].top = top; + mouse_region[index].left = left; + mouse_region[index].bottom = bottom; + mouse_region[index].right = right; + } + return; +} +/* ------------------------------------------------------------------------ */ +int CheckMouseRegion(int x, int y) +{ + int i; + int found; + + found = 0; + + for (i = 0; i < MAX_MOUSE_REGION && !found; i++) { + if (mouse_region[i].enable && + x <= mouse_region[i].right && + x >= mouse_region[i].left && + y <= mouse_region[i].bottom && + y >= mouse_region[i].top) + found = 1; + } + if (!found) + return -1; + return (i - 1); +} +/* ------------------------------------------------------------------------ */ +/* + * GRAPHIC : pixmap writing of letters & numbers + * + */ +/* ------------------------------------------------------------------------ */ +static void chiffre(int ch, int xx, int yy) +{ + XCopyArea(dpy, numpix.pixmap, wmg.pixmap, NormalGC, + zapnum[ch][0], zapnum[ch][1], zapnum[ch][2], zapnum[ch][3], xx, yy); + + return; +} +/* ------------------------------------------------------------------------ */ +static int lettre(char c, int xx, int yy) +{ + int i; + if (c == '°') + i = 288; + else + switch (toupper(c)) { + case '0': + i = 0; + break; + case '1': + i = 6; + break; + case '2': + i = 12; + break; + case '3': + i = 18; + break; + case '4': + i = 24; + break; + case '5': + i = 30; + break; + case '6': + i = 36; + break; + case '7': + i = 42; + break; + case '8': + i = 48; + break; + case '9': + i = 54; + break; + case '+': + i = 60; + break; + case 'A': + i = 66; + break; + case 'B': + i = 72; + break; + case 'C': + i = 78; + break; + case 'D': + i = 84; + break; + case 'E': + i = 90; + break; + case 'F': + i = 96; + break; + case 'G': + i = 102; + break; + case 'H': + i = 108; + break; + case 'I': + i = 114; + break; + case 'J': + i = 120; + break; + case 'K': + i = 126; + break; + case 'L': + i = 132; + break; + case 'M': + i = 138; + break; + case 'N': + i = 144; + break; + case 'O': + i = 150; + break; + case 'P': + i = 156; + break; + case 'Q': + i = 162; + break; + case 'R': + i = 168; + break; + case 'S': + i = 174; + break; + case 'T': + i = 180; + break; + case 'U': + i = 186; + break; + case 'V': + i = 192; + break; + case 'W': + i = 198; + break; + case 'X': + i = 204; + break; + case 'Y': + i = 210; + break; + case 'Z': + i = 216; + break; + case ' ': + i = 222; + break; + case ':': + i = 228; + break; + case '/': + i = 234; + break; + case '!': + i = 240; + break; + case '*': + i = 246; + break; + case '-': + i = 252; + break; + case '.': + i = 258; + break; + case '=': + i = 264; + break; + case '#': + i = 270; + break; + case '<': + i = 276; + break; + case '>': + i = 282; + break; + case '"': + i = 294; + break; + case '\'': + i = 300; + break; + case ',': + i = 306; + break; + case '@': + i = 312; + break; + case '(': + i = 318; + break; + case ')': + i = 324; + break; + case '&': + i = 330; + break; + case '~': + i = 336; + break; + case '£': + i = 342; + break; + case 'µ': + i = 348; + break; + case '{': + i = 354; + break; + case '}': + i = 360; + break; + case '[': + i = 366; + break; + case ']': + i = 372; + break; + case '\\': + i = 378; + break; + case '|': + i = 384; + break; + case '?': + i = 390; + break; + case '%': + i = 396; + break; + default: + i = 222; + break; + } + + XCopyArea(dpy, txtpix.pixmap, wmg.pixmap, NormalGC, + i, 0, 6, 10, xx, yy); + return xx + 6; +} +/* ------------------------------------------------------------------------ */ +static void write_icon(char *txt, int x, int y) +{ + int p, ok; + p = 0; + +#ifdef DEBUG + fprintf(stdout, "%s_\n", txt); +#endif + ok = TRUE; + while (ok) { + if (txt[p] == '\0' || x > DIAMETRE - 5) { + ok = FALSE; + } else { + x = lettre(txt[p], x, y); + p++; + } + } + return; +} +/* ------------------------------------------------------------------------ */ +static void press_but(int ckm) +{ + switch (ckm) { + case 5: + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 38, 20, 9, 2, 52); + RedrawWindowXYWH(2, 52, 20, 9); + break; + case 6: + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 20, 38, 20, 9, 22, 52); + RedrawWindowXYWH(22, 52, 20, 9); + break; + case 7: + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 40, 38, 20, 9, 42, 52); + RedrawWindowXYWH(42, 52, 20, 9); + break; + default: + break; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void release_but(int ckm) +{ + switch (ckm) { + case 5: + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 28, 20, 9, 2, 52); + RedrawWindowXYWH(2, 52, 20, 9); + break; + case 6: + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 20, 28, 20, 9, 22, 52); + RedrawWindowXYWH(22, 52, 20, 9); + break; + case 7: + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 40, 28, 20, 9, 42, 52); + RedrawWindowXYWH(42, 52, 20, 9); + break; + default: + break; + } + return; +} +/* ------------------------------------------------------------------------ */ +/* + * MENU SELECTION & ACTIONS + */ +/* ------------------------------------------------------------------------ */ +void screen_back() +{ + AddMouseRegion(0, 0, 0, 0, 0); + if (p_type == PTRANDOM) { + stoprand = STOP_RANDOM_FACTOR; + addlong = dv_long; + addlat = dv_lat; + } + gotoscr = 1; + while (gotoscr != 0) { + switch (gotoscr) { + case 1: + screen_1(); + break; + case 2: + screen_2(); + break; + case 3: + screen_3(); + break; + case 4: + screen_4(); + break; + case 5: + screen_5(); + break; + case 6: + screen_6(); + break; + case 7: + screen_7(); + break; + default: + break; + } + XFlush(dpy); + } +/* + * put old environment + */ + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pixmask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet); + + AddMouseRegion(0, 5, 5, DIAMETRE - 4, DIAMETRE - 4); + stoprand = FALSE; + do_something = TRUE; + + return; +} +/* ------------------------------------------------------------------------ */ +static void display_pos(double la, double lo) +{ + int c, i, j, k, l, neg; + + if (la > 0) { + neg = 10; + } else { + neg = 11; + la *= -1; + } + i = floor(la / 10.0); + la -= 10 * i; + j = floor(la); + la -= j; + la *= 60; + k = floor(la / 10.0); + la -= 10 * k; + l = floor(la); + + if (i == 0) { + i = neg; + neg = 10; + } + chiffre(neg, platd[1][0], platd[1][1]); + chiffre(i, platd[2][0], platd[2][1]); + chiffre(j, platd[3][0], platd[3][1]); + chiffre(k, platm[0][0], platd[0][1]); + chiffre(l, platm[1][0], platd[1][1]); + + if (lo > 0) { + neg = 12; + } else { + neg = 11; + lo *= -1; + } + c = floor(lo / 100.0); + lo -= c * 100; + if (c > 0) { + if (neg == 11) + neg = 13; + } else { + if (neg == 11) { + c = neg; + } else { + c = 10; + } + neg = 12; + } + i = floor(lo / 10.0); + lo -= 10 * i; + j = floor(lo); + lo -= j; + lo *= 60; + k = floor(lo / 10.0); + lo -= 10 * k; + l = floor(lo); + if (i == 0 && c > 9) { + i = c; + c = 10; + } + chiffre(neg, plongd[0][0], plongd[0][1]); + chiffre(c, plongd[1][0], plongd[1][1]); + chiffre(i, plongd[2][0], plongd[2][1]); + chiffre(j, plongd[3][0], plongd[3][1]); + chiffre(k, plongm[0][0], plongm[0][1]); + chiffre(l, plongm[1][0], plongm[1][1]); + + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + return; +} +/* ------------------------------------------------------------------------ */ +void rotation_terre(int x, int y, int lat_flag) +{ +/* + * earth rotate after (while) a clic + */ + double mx, my; + mx = (double) ((double) x - DIAMETRE / 2 + 0.5) / zoom * cos(v_lat) * sens; + if (lat_flag) { + my = -(double) ((double) y - DIAMETRE / 2 + 0.5) * sens / zoom; + if (my > 0.0) + my += ABS(sin(v_lat) * ((double) x - DIAMETRE / 2 + 0.5) / zoom); + else + my -= ABS(sin(v_lat) * ((double) x - DIAMETRE / 2 + 0.5) / zoom); + } else { + my = 0; + } + if (p_type == PTRANDOM) { + stoprand = STOP_RANDOM_FACTOR; + addlong = dv_long; + addlat = dv_lat; + } + addlong += mx * RATIO_ROTATE; + addlat += my * RATIO_ROTATE; + + do_something = TRUE; + return; +} +/* ------------------------------------------------------------------------ */ +static void move_earth(double vla, double vlo) +{ + addlat += vla; + addlong += vlo; + + + switch (p_type) { + case PTSUNREL: + setViewPos(sun_lat * 180. / PI + addlat, + sun_long * 180. / PI + addlong); + break; + + case PTFIXED: + case PTRANDOM: + setViewPos(addlat, addlong); + break; + default: + break; + } + display_pos(dv_lat, dv_long); + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_1() +{ + int ok, ckm, sensadd, waitrel, not3; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 1\n"); +#endif + tin = getimev(); + waitrel = 0; + ckm = 0; + sensadd = 1; + not3 = TRUE; + + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, screenpos.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, screenpos.mask, ShapeSet); + + XCopyArea(dpy, screenpos.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + + AddMouseRegion(1, platd[0][0], platd[0][1], platd[3][0] + 9, platd[3][1] + 12); + AddMouseRegion(2, platm[0][0], platm[0][1], platm[1][0] + 9, platm[1][1] + 12); + AddMouseRegion(3, plongd[0][0], plongd[0][1], plongd[3][0] + 9, plongd[3][1] + 12); + AddMouseRegion(4, plongm[0][0], plongm[0][1], plongm[1][0] + 9, plongm[1][1] + 12); + AddMouseRegion(5, 1, 51, 21, 61); + AddMouseRegion(6, 22, 51, 41, 61); + AddMouseRegion(7, 42, 51, 62, 61); + + display_pos(dv_lat, dv_long); + + ok = TRUE; + while (ok) { + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + not3 = TRUE; + sensadd = 1; + break; + case 2: + not3 = TRUE; + sensadd = -1; + break; + case 3: + not3 = FALSE; + if (ckm < 5) + gotoscr = 0; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + + } + } + usleep(VAL_USLEEP_SHORT); + if (waitrel && not3) { + if (ckm == 1) { + move_earth(sens * sensadd * 1.0, 0.0); + usleep(VAL_USLEEP); + } + if (ckm == 2) { + move_earth(sens * sensadd * 1.0 / 60.0, 0.0); + usleep(VAL_USLEEP); + } + if (ckm == 3) { + move_earth(0.0, sens * sensadd * 1.0); + usleep(VAL_USLEEP); + } + if (ckm == 4) { + move_earth(0.0, sens * sensadd * 1.0 / 60.0); + usleep(VAL_USLEEP); + } + } + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 1) + gotoscr = 0; + if (gotoscr != 1) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void display_date(double la, double lo) +{ + char datest[32]; + time_t t; + int i, j; + + write_icon(" time :", 2, 2); + RedrawWindowXYWH(2, 2, DIAMETRE - 1, DIAMETRE - 1); + + write_icon(" GMT+long.", 2, 14); + RedrawWindowXYWH(2, 14, DIAMETRE - 1, DIAMETRE - 1); + + t = trend.tv_sec; + t += (int) (floor((lo + 7.5) / 15.0) * 3600); +/*** pb near 2038 ***/ + + strftime(datest, 30, "%x", gmtime(&t)); + + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + + write_icon(datest, 2 + i * 6, 26); + RedrawWindowXYWH(2, 26, DIAMETRE - 1, DIAMETRE - 1); + + strftime(datest, 30, "%X", gmtime(&t)); + + i = 10 - strlen(datest); + if (i < 0) { + i = 0; + while (datest[i] != '\0') { + if (datest[i] != ' ') { + i++; + } else { + j = i; + do { + datest[j] = datest[j + 1]; + j++; + } + while (datest[j - 1] != '\0'); + } + } + i = 0; + } else { + i = i / 2; + } + + write_icon(datest, 2 + i * 6, 38); + RedrawWindowXYWH(2, 38, DIAMETRE - 1, DIAMETRE - 1); + + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_2() +{ + int ok, ckm, waitrel; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 2\n"); +#endif + tin = getimev(); + waitrel = 0; + ckm = 0; + + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + + XCopyArea(dpy, scrdate.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + + display_date(dv_lat, dv_long); + + ok = TRUE; + while (ok) { + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + break; + case 2: + break; + case 3: + if (ckm < 5) + gotoscr = 0; + break; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + + } + } + usleep(VAL_USLEEP_SHORT); + + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 2) + gotoscr = 0; + if (gotoscr != 2) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void display_zoom() +{ + char datest[32], dstr[32]; + int i; + + write_icon(" delay :", 2, 2); + RedrawWindowXYWH(2, 2, DIAMETRE - 1, DIAMETRE - 1); + + sprintf(dstr, "%f", delay); + dstr[8] = '\0'; + i = strlen(dstr) - 1; + while (i > 0) { + if (dstr[i] == '0') { + dstr[i] = '\0'; + i--; + } else { + i = 0; + } + } + i = strlen(dstr) - 1; + if (dstr[i] == '.') + dstr[i] = '\0'; + sprintf(datest, "%s s", dstr); + + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 14); + RedrawWindowXYWH(2, 14, DIAMETRE - 1, DIAMETRE - 1); + + write_icon(" zoom :", 2, 26); + RedrawWindowXYWH(2, 26, DIAMETRE - 1, DIAMETRE - 1); + + sprintf(datest, "%.3f", zoom); + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 38); + RedrawWindowXYWH(2, 38, DIAMETRE - 1, DIAMETRE - 1); + + return; +} +/* ------------------------------------------------------------------------ */ +static void move_delay(int factor) +{ + if (factor == 1) { + if (delay < (double) VAL_USLEEP / 1000000) + delay = (double) VAL_USLEEP / 1000000; + else if (delay < 0.1) { + delay += 0.01; + if (delay > 0.1) + delay = 0.2; + } else if (delay < 1.) { + delay += 0.1; + if (delay > 1.0) + delay = 2.; + } else if (delay < 60.) + delay += 1.; + else if (delay < 300.) + delay += 10.; + else if (delay < 3600.) + delay += 60.; + else if (delay < MAX_DELAY_SEC) + delay += 360.; + + if (delay > MAX_DELAY_SEC) + delay = MAX_DELAY_SEC; + } else { + if (delay > 3600.) + delay -= 360.; + else if (delay > 300.) + delay -= 60.; + else if (delay > 60.) + delay -= 10.; + else if (delay > 1.) + delay -= 1.; + else if (delay > 0.1) + delay -= 0.1; + else if (delay > (double) VAL_USLEEP / 1000000) + delay -= 0.01; + else + delay = 0.0; + + if (delay < (double) VAL_USLEEP / 1000000) + delay = 0.0; + } + + tdelay.tv_sec = (int) floor(delay); + tdelay.tv_usec = (int) ((delay - tdelay.tv_sec) * 1000000); + + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 14); + + display_zoom(); + return; +} +/* ------------------------------------------------------------------------ */ +void zooming(int facto) +{ + if (facto) + zoom /= ZOOM_FACTOR; + else + zoom *= ZOOM_FACTOR; + zoom = MAX(zoom, ZOOM_MIN); + zoom = MIN(zoom, ZOOM_MAX); + if (p_type == PTRANDOM) { + addlong = dv_long; + addlat = dv_lat; + stoprand = STOP_RANDOM_FACTOR; + } + calcDistance(); + do_something = TRUE; + return; +} +/* ------------------------------------------------------------------------ */ +static void move_zoom(int factor) +{ + if (factor == -1) + zooming(1); + else + zooming(0); + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 38); + display_zoom(); + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_3() +{ + int ok, ckm, waitrel, sensadd, not3; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 3\n"); +#endif + tin = getimev(); + waitrel = 0; + ckm = 0; + sensadd = 0; + not3 = TRUE; + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + + XCopyArea(dpy, scrdate.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + + AddMouseRegion(1, 2, 14, DIAMETRE - 2, 25); + AddMouseRegion(2, 2, 38, DIAMETRE - 2, 49); + display_zoom(); + + ok = TRUE; + while (ok) { + + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + not3 = TRUE; + sensadd = 1; + break; + case 2: + not3 = TRUE; + sensadd = -1; + break; + case 3: + not3 = FALSE; + if (ckm < 5) + gotoscr = 0; + break; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + + } + } + usleep(VAL_USLEEP_SHORT); + if (waitrel && not3) { + if (ckm == 1) { + move_delay(sensadd); + usleep(2 * VAL_USLEEP); + } + if (ckm == 2) { + move_zoom(sensadd); + usleep(VAL_USLEEP); + } + } + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 3) + gotoscr = 0; + if (gotoscr != 3) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void display_light() +{ + char datest[32]; + int i; + + write_icon(" light :", 2, 2); + RedrawWindowXYWH(2, 2, DIAMETRE - 1, DIAMETRE - 1); + + sprintf(datest, "%.2f", ambient_light); + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 14); + RedrawWindowXYWH(2, 14, DIAMETRE - 1, DIAMETRE - 1); + + write_icon(" dawn :", 2, 26); + RedrawWindowXYWH(2, 26, DIAMETRE - 1, DIAMETRE - 1); + + dawn = (1.0 - dawn) * 2.0; + sprintf(datest, "%.2f", dawn); + dawn = (1.0 - dawn / 2.0); + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 38); + RedrawWindowXYWH(2, 38, DIAMETRE - 1, DIAMETRE - 1); + + return; +} +/* ------------------------------------------------------------------------ */ +static void move_light(int factor) +{ + ambient_light += factor / 20.0; + ambient_light = MAX(0.0, ambient_light); + ambient_light = MIN(1.0, ambient_light); + aml = (int) floor(ambient_light * 256); + + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 14); + + display_light(); + return; +} +/* ------------------------------------------------------------------------ */ +static void move_dawn(int factor) +{ + dawn = (1.0 - dawn) * 2.0; + dawn += factor / 20.0; + dawn = MAX(0.0, dawn); + dawn = MIN(1.0, dawn); + dawn = (1.0 - dawn / 2.0); + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 38); + + display_light(); + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_4() +{ + int ok, ckm, waitrel, sensadd, not3; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 4\n"); +#endif + tin = getimev(); + waitrel = 0; + ckm = 0; + sensadd = 0; + not3 = TRUE; + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + + XCopyArea(dpy, scrdate.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + + AddMouseRegion(1, 2, 14, DIAMETRE - 2, 25); + AddMouseRegion(2, 2, 38, DIAMETRE - 2, 49); + display_light(); + + ok = TRUE; + while (ok) { + + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + not3 = TRUE; + sensadd = 1; + break; + case 2: + not3 = TRUE; + sensadd = -1; + break; + case 3: + not3 = FALSE; + if (ckm < 5) + gotoscr = 0; + break; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + } + } + usleep(VAL_USLEEP_SHORT); + if (waitrel && not3) { + if (ckm == 1) { + move_light(sensadd); + usleep(VAL_USLEEP); + } + if (ckm == 2) { + move_dawn(sensadd); + usleep(VAL_USLEEP); + } + } + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 4) + gotoscr = 0; + if (gotoscr != 4) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void display_accel() +{ + char datest[32]; + int i; + + write_icon(" accel :", 2, 2); + RedrawWindowXYWH(2, 2, DIAMETRE - 1, DIAMETRE - 1); + + if (time_multi < 24.0) + sprintf(datest, "%.1f", time_multi); + else + sprintf(datest, "%.0f", time_multi); + + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 14); + RedrawWindowXYWH(2, 14, DIAMETRE - 1, DIAMETRE - 1); + + write_icon("night map:", 2, 26); + RedrawWindowXYWH(2, 26, DIAMETRE - 1, DIAMETRE - 1); + + if (use_nightmap) + write_icon(" yes ", 2, 38); + else + write_icon(" no ", 2, 38); + + RedrawWindowXYWH(2, 38, DIAMETRE - 1, DIAMETRE - 1); + + return; +} +/* ------------------------------------------------------------------------ */ +static void move_accel(int factor) +{ + if (factor == 1) { + if (time_multi < 1.0) + time_multi = 1.0; + if (time_multi < 24.0) + time_multi += 0.2; + else if (time_multi < 60.0) { + time_multi = floor(time_multi); + time_multi += 1.0; + } else if (time_multi < 120.0) { + time_multi = floor(time_multi); + time_multi += 2.0; + } else if (time_multi < 240.0) { + time_multi = floor(time_multi); + time_multi += 4.0; + } else if (time_multi < 600.0) { + time_multi = floor(time_multi); + time_multi += 10.0; + } else if (time_multi < 1200.0) { + time_multi = floor(time_multi); + time_multi += 20.0; + } else if (time_multi < 2400.0) { + time_multi = floor(time_multi); + time_multi += 40.0; + } else if (time_multi < 6000.0) { + time_multi = floor(time_multi); + time_multi += 100.0; + } else if (time_multi < 12000.0) { + time_multi = floor(time_multi); + time_multi += 200.0; + } else if (time_multi < 24000.0) { + time_multi = floor(time_multi); + time_multi += 400.0; + } else if (time_multi < 60000.0) { + time_multi = floor(time_multi); + time_multi += 1000.0; + } else if (time_multi < 120000.0) { + time_multi = floor(time_multi); + time_multi += 2000.0; + } else if (time_multi < 240000.0) { + time_multi = floor(time_multi); + time_multi += 4000.0; + } else { + time_multi = floor(time_multi); + time_multi += 8000.0; + } + if (time_multi > MAX_MULTI_COEF) + time_multi = MAX_MULTI_COEF; + } else { + if (time_multi < 24.1) + time_multi -= 0.2; + else if (time_multi < 60.2) { + time_multi = floor(time_multi); + time_multi -= 1.0; + } else if (time_multi < 121.0) { + time_multi = floor(time_multi); + time_multi -= 2.0; + } else if (time_multi < 241.0) { + time_multi = floor(time_multi); + time_multi -= 4.0; + } else if (time_multi < 601.0) { + time_multi = floor(time_multi); + time_multi -= 10.0; + } else if (time_multi < 1201.0) { + time_multi = floor(time_multi); + time_multi -= 20.0; + } else if (time_multi < 2401.0) { + time_multi = floor(time_multi); + time_multi -= 40.0; + } else if (time_multi < 6001.0) { + time_multi = floor(time_multi); + time_multi -= 100.0; + } else if (time_multi < 12001.0) { + time_multi = floor(time_multi); + time_multi -= 200.0; + } else if (time_multi < 24001.0) { + time_multi = floor(time_multi); + time_multi -= 400.0; + } else if (time_multi < 60001.0) { + time_multi = floor(time_multi); + time_multi -= 1000.0; + } else if (time_multi < 120001.0) { + time_multi = floor(time_multi); + time_multi -= 2000.0; + } else if (time_multi < 240001.0) { + time_multi = floor(time_multi); + time_multi -= 4000.0; + } else { + time_multi = floor(time_multi); + time_multi -= 8000.0; + } + + if (time_multi > 24.0) + time_multi = floor(time_multi); + if (time_multi < 1.0) + time_multi = 1.0; + } + + tini = tlast; + tbase = trend; + + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 14); + + display_accel(); + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_5() +{ + int ok, ckm, waitrel, sensadd, not3; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 5\n"); +#endif + tin = getimev(); + waitrel = 0; + ckm = 0; + sensadd = 0; + not3 = TRUE; + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + + XCopyArea(dpy, scrdate.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + + AddMouseRegion(1, 2, 14, DIAMETRE - 2, 25); + AddMouseRegion(2, 2, 38, DIAMETRE - 2, 49); + display_accel(); + + ok = TRUE; + while (ok) { + + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + not3 = TRUE; + sensadd = 1; + break; + case 2: + not3 = TRUE; + sensadd = -1; + break; + case 3: + not3 = FALSE; + if (ckm < 5) + gotoscr = 0; + break; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + + } + } + usleep(VAL_USLEEP_SHORT); + if (waitrel && not3) { + if (ckm == 1) { + move_accel(sensadd); + usleep(VAL_USLEEP); + } + if (ckm == 2) { + not3 = FALSE; + if (use_nightmap) { + use_nightmap = FALSE; + display_accel(); + } else { + if (use_nmap_ini) { + use_nightmap = TRUE; + display_accel(); + } + } + usleep(VAL_USLEEP); + } + } + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 5) + gotoscr = 0; + if (gotoscr != 5) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void display_dlat() +{ + char datest[32]; + int i, d, m, nega, nego; + + write_icon(" dlat :", 2, 2); + RedrawWindowXYWH(2, 2, DIAMETRE - 1, DIAMETRE - 1); + if (dlat < 0.0) { + nega = TRUE; + dlat *= -1; + } else + nega = FALSE; + + m = (int) floor((dlat - floor(dlat)) * 60.0); + d = (int) floor(dlat); + + if (nega) { + sprintf(datest, "-%d°%02d'", d, m); + dlat *= -1; + } else + sprintf(datest, "%d°%02d'", d, m); + + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 14); + RedrawWindowXYWH(2, 14, DIAMETRE - 1, DIAMETRE - 1); + + write_icon(" dlong :", 2, 26); + RedrawWindowXYWH(2, 26, DIAMETRE - 1, DIAMETRE - 1); + + + if (dlong < 0.0) { + nego = TRUE; + dlong *= -1; + } else + nego = FALSE; + + m = (int) floor((dlong - floor(dlong)) * 60.0); + d = (int) floor(dlong); + + if (nego) { + sprintf(datest, "-%d°%02d'", d, m); + dlong *= -1; + } else + sprintf(datest, "%d°%02d'", d, m); + + i = 10 - strlen(datest); + if (i < 0) + i = 0; + else + i = i / 2; + write_icon(datest, 2 + i * 6, 38); + RedrawWindowXYWH(2, 38, DIAMETRE - 1, DIAMETRE - 1); + + return; +} +/* ------------------------------------------------------------------------ */ +static void move_dlat(int factor) +{ + dlat += factor / 4.0; + if (dlat > MAX_DELTA_LONG) + dlat = MAX_DELTA_LONG; + if (dlat < -MAX_DELTA_LONG) + dlat = -MAX_DELTA_LONG; + if (dlat < 0.25 && dlat > -0.25) + dlat = 0; + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 14); + if (dlat != 0.) + p_type = PTFIXED; + display_dlat(); + return; +} +/* ------------------------------------------------------------------------ */ +static void move_dlong(int factor) +{ + dlong += factor / 4.0; + if (dlong > MAX_DELTA_LONG) + dlong = MAX_DELTA_LONG; + if (dlong < -MAX_DELTA_LONG) + dlong = -MAX_DELTA_LONG; + if (dlong < 0.25 && dlong > -0.25) + dlong = 0; + XCopyArea(dpy, scrdiv.pixmap, wmg.pixmap, NormalGC, + 0, 15, 60, 10, 2, 38); + if (dlong != 0.) + p_type = PTFIXED; + display_dlat(); + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_6() +{ + int ok, ckm, waitrel, sensadd, not3; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 6\n"); +#endif + tin = getimev(); + waitrel = 0; + sensadd = 0; + ckm = 0; + not3 = TRUE; + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + + XCopyArea(dpy, scrdate.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + AddMouseRegion(1, 2, 14, DIAMETRE - 2, 25); + AddMouseRegion(2, 2, 38, DIAMETRE - 2, 49); + + display_dlat(); + + ok = TRUE; + while (ok) { + + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + not3 = TRUE; + sensadd = 1; + break; + case 2: + not3 = TRUE; + sensadd = -1; + break; + case 3: + not3 = FALSE;; + if (ckm < 5) + gotoscr = 0; + break; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + + } + } + usleep(VAL_USLEEP_SHORT); + if (waitrel && not3) { + if (ckm == 1 && p_type != PTRANDOM) { + move_dlat(sensadd); + usleep(VAL_USLEEP); + } + if (ckm == 2 && p_type != PTRANDOM) { + move_dlong(sensadd); + usleep(VAL_USLEEP); + } + } + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 6) + gotoscr = 0; + if (gotoscr != 6) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ +static void display_type() +{ + char c, cc, mess[12]; + + write_icon(" view :", 2, 2); + RedrawWindowXYWH(2, 2, DIAMETRE - 1, DIAMETRE - 1); + + if (p_type == PTFIXED) { + c = '>'; + cc = '<'; + } else { + c = ' '; + cc = ' '; + } + sprintf(mess, "%c move %c", c, cc); + write_icon(mess, 2, 14); + RedrawWindowXYWH(2, 14, DIAMETRE - 1, DIAMETRE - 1); + if (p_type == PTSUNREL) { + c = '>'; + cc = '<'; + } else { + c = ' '; + cc = ' '; + } + sprintf(mess, "%c sun %c", c, cc); + write_icon(mess, 2, 26); + RedrawWindowXYWH(2, 26, DIAMETRE - 1, DIAMETRE - 1); + if (p_type == PTRANDOM) { + c = '>'; + cc = '<'; + } else { + c = ' '; + cc = ' '; + } + sprintf(mess, "%c random %c", c, cc); + write_icon(mess, 2, 38); + RedrawWindowXYWH(2, 38, DIAMETRE - 1, DIAMETRE - 1); + + return; +} +/* ------------------------------------------------------------------------ */ +static void screen_7() +{ + int ok, ckm, waitrel, sensadd, not3; + struct timeval tin; + +#ifdef DEBUG + fprintf(stdout, "scr 7\n"); +#endif + tin = getimev(); + waitrel = 0; + sensadd = 0; + ckm = 0; + not3 = TRUE; + + XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, scrdate.mask, ShapeSet); + + XCopyArea(dpy, scrdate.pixmap, wmg.pixmap, NormalGC, 0, 0, DIAMETRE, DIAMETRE, 0, 0); + AddMouseRegion(1, 2, 14, DIAMETRE - 2, 25); + AddMouseRegion(2, 2, 26, DIAMETRE - 2, 37); + AddMouseRegion(3, 2, 38, DIAMETRE - 2, 49); + + display_type(0); + + ok = TRUE; + while (ok) { + + while (XPending(dpy)) { + XNextEvent(dpy, &Event); + switch (Event.type) { + case Expose: + RedrawWindowXYWH(0, 0, DIAMETRE, DIAMETRE); + break; + case DestroyNotify: + XCloseDisplay(dpy); + exit(0); + break; + case ButtonPress: + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + waitrel = 1; + press_but(ckm); + switch (Event.xbutton.button) { + case 1: + not3 = TRUE; + if (ckm < 4 && ckm > 0) + sensadd = ckm; + break; + case 2: + not3 = TRUE; + break; + case 3: + not3 = FALSE; + if (ckm < 5) + gotoscr = 0; + break; + default: + break; + } + break; + case ButtonRelease: + release_but(ckm); + waitrel = ckm; + ckm = CheckMouseRegion(Event.xbutton.x, Event.xbutton.y); + if (waitrel == ckm) { + switch (ckm) { + case 5: + gotoscr--; + if (gotoscr == 0) + gotoscr = NUM_SCREEN; + break; + case 6: + gotoscr++; + if (gotoscr > NUM_SCREEN) + gotoscr = 1; + break; + case 7: + gotoscr = 0; + default: + break; + } + } + ckm = 0; + waitrel = 0; + tin = getimev(); + break; + default: + break; + } + } + usleep(VAL_USLEEP_SHORT); + if (waitrel && not3 && sensadd) { + if (sensadd == 2) { + if (p_type != PTSUNREL) { + p_type = PTSUNREL; + dlat = 0; + dlong = 0; + display_type(); + } + } + if (sensadd == 1) { + if (p_type != PTFIXED) { + p_type = PTFIXED; + display_type(); + } + } + if (sensadd == 3) { + if (p_type != PTRANDOM) { + p_type = PTRANDOM; + dlat = 0; + dlong = 0; + display_type(); + } + } + } + sensadd = 0; + if (waitrel == 0 && diftimev(getimev(), tin).tv_sec > SCREEN_WAIT && gotoscr == 7) + gotoscr = 0; + if (gotoscr != 7) + ok = FALSE; + } + return; +} +/* ------------------------------------------------------------------------ */ diff --git a/wmglobe/src/wraster.h b/wmglobe/src/wraster.h new file mode 100644 index 0000000..0f88d46 --- /dev/null +++ b/wmglobe/src/wraster.h @@ -0,0 +1,398 @@ + +/* + * Raster graphics library + * + * Copyright (c) 1997, 1998 Alfredo K. Kojima + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Environment variables: + * + * WRASTER_GAMMA // + * gamma correction value. Must be greater than 0 + * Only for PseudoColor visuals. + * + * Default: + * WRASTER_GAMMA 1/1/1 + * + * + * If you want a specific value for a screen, append the screen number + * preceded by a hash to the variable name as in + * WRASTER_GAMMA#1 + * for screen number 1 + */ + +#ifndef RLRASTER_H_ +#define RLRASTER_H_ + + +/* version of the header for the library: 0.11 */ +#define WRASTER_HEADER_VERSION 11 + +#ifdef HAVE_ALLOCA_H +#include +#endif + + +#include +#include + +#ifdef XSHM +#include +#endif + +/* RM_MATCH or RM_DITHER */ +#define RC_RenderMode (1<<0) + +/* number of colors per channel for colormap in PseudoColor mode */ +#define RC_ColorsPerChannel (1<<1) + +/* do gamma correction */ +#define RC_GammaCorrection (1<<2) + +/* visual id to use */ +#define RC_VisualID (1<<3) + +/* shared memory usage */ +#define RC_UseSharedMemory (1<<4) + +/* use default instead of best visual */ +#define RC_DefaultVisual (1<<5) + +typedef struct RContextAttributes { + int flags; + int render_mode; + int colors_per_channel; /* for PseudoColor */ + float rgamma; /* gamma correction for red, */ + float ggamma; /* green, */ + float bgamma; /* and blue */ + VisualID visualid; /* visual ID to use */ + int use_shared_memory; /* True of False */ +} RContextAttributes; + + +/* + * describes a screen in terms of depth, visual, number of colors + * we can use, if we should do dithering, and what colors to use for + * dithering. + */ +typedef struct RContext { + Display *dpy; + int screen_number; + Colormap cmap; + + RContextAttributes *attribs; + + GC copy_gc; + + Visual *visual; + int depth; + Window drawable; /* window to pass for XCreatePixmap(). */ + /* generally = root */ + int vclass; + + unsigned long black; + unsigned long white; + + int red_offset; /* only used in 24bpp */ + int green_offset; + int blue_offset; + + /* only used for pseudocolor and grayscale */ + + XStandardColormap *std_rgb_map; /* standard RGB colormap */ + XStandardColormap *std_gray_map; /* standard grayscale colormap */ + + int ncolors; /* total number of colors we can use */ + XColor *colors; /* internal colormap */ + + struct { + unsigned int use_shared_pixmap:1; + } flags; +} RContext; + + +typedef struct RColor { + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; +} RColor; + + +typedef struct RHSVColor { + unsigned short hue; /* 0-359 */ + unsigned char saturation; /* 0-255 */ + unsigned char value; /* 0-255 */ +} RHSVColor; + + + +typedef struct RPoint { + int x, y; +} RPoint; + + +typedef struct RSegment { + int x1, y1, x2, y2; +} RSegment; + + +/* + * internal 24bit+alpha image representation + */ +typedef struct RImage { + unsigned width, height; /* size of the image */ + RColor background; /* background color */ + unsigned char *data[4]; /* image data (R,G,B,A) */ +} RImage; + + +/* + * internal wrapper for XImage. Used for shm abstraction + */ +typedef struct RXImage { + XImage *image; + + /* Private data. Do not access */ +#ifdef XSHM + XShmSegmentInfo info; + char is_shared; +#endif +} RXImage; + + +/* note that not all operations are supported in all functions */ +enum { + RClearOperation, /* clear with 0 */ + RCopyOperation, + RNormalOperation, /* same as combine */ + RAddOperation, + RSubtractOperation +}; + + +/* image display modes */ +enum { + RDitheredRendering = 0, + RBestMatchRendering = 1 +}; + +/* bw compat */ +#define RM_DITHER RDitheredRendering +#define RM_MATCH RBestMatchRendering + +enum { + RAbsoluteCoordinates = 0, + RRelativeCoordinates = 1 +}; + + +enum { + RSunkenBevel = -1, + RRaisedBevel = 1 +}; + +/* bw compat */ +#define RBEV_SUNKEN RSunkenBevel +/* 1 pixel wide */ +#define RBEV_RAISED RRaisedBevel +/* 1 pixel wide on top/left 2 on bottom/right */ +#define RBEV_RAISED2 2 +/* 2 pixel width */ +#define RBEV_RAISED3 3 + +enum { + RHorizontalGradient = 2, + RVerticalGradient = 3, + RDiagonalGradient = 4 +}; + +/* for backwards compatibility */ +#define RGRD_HORIZONTAL RHorizontalGradient +#define RGRD_VERTICAL RVerticalGradient +#define RGRD_DIAGONAL RDiagonalGradient + + + +/* error codes */ +#define RERR_NONE 0 +#define RERR_OPEN 1 /* cant open file */ +#define RERR_READ 2 /* error reading from file */ +#define RERR_WRITE 3 /* error writing to file */ +#define RERR_NOMEMORY 4 /* out of memory */ +#define RERR_NOCOLOR 5 /* out of color cells */ +#define RERR_BADIMAGEFILE 6 /* image file is corrupted or invalid */ +#define RERR_BADFORMAT 7 /* image file format is unknown */ +#define RERR_BADINDEX 8 /* no such image index in file */ + +#define RERR_BADVISUALID 16 /* invalid visual ID requested for context */ + +#define RERR_XERROR 127 /* internal X error */ +#define RERR_INTERNAL 128 /* should not happen */ + + +/* + * Returns a NULL terminated array of strings containing the + * supported formats, such as: TIFF, XPM, PNG, JPEG, PPM, GIF + */ +char **RSupportedFileFormats(void); + +void RFreeStringList(char **list); + +/* + * Xlib contexts + */ +RContext *RCreateContext(Display * dpy, int screen_number, + RContextAttributes * attribs); + +void RDestroyContext(RContext * context); + +Bool RGetClosestXColor(RContext * context, RColor * color, XColor * retColor); + +/* + * RImage creation + */ +RImage *RCreateImage(unsigned width, unsigned height, int alpha); + +RImage *RCreateImageFromXImage(RContext * context, XImage * image, XImage * mask); + +RImage *RCreateImageFromDrawable(RContext * context, Drawable drawable, + Pixmap mask); + +RImage *RLoadImage(RContext * context, char *file, int index); + + +void RDestroyImage(RImage * image); + +RImage *RGetImageFromXPMData(RContext * context, char **data); + +/* + * RImage storing + */ +Bool RSaveImage(RImage * image, char *filename, char *format); + +/* + * Area manipulation + */ +RImage *RCloneImage(RImage * image); + +RImage *RGetSubImage(RImage * image, int x, int y, unsigned width, + unsigned height); + +void RCombineImageWithColor(RImage * image, RColor * color); + +void RCombineImages(RImage * image, RImage * src); + +void RCombineArea(RImage * image, RImage * src, int sx, int sy, unsigned width, + unsigned height, int dx, int dy); + +void RCombineImagesWithOpaqueness(RImage * image, RImage * src, int opaqueness); + +void RCombineAreaWithOpaqueness(RImage * image, RImage * src, int sx, int sy, + unsigned width, unsigned height, int dx, int dy, + int opaqueness); + +RImage *RScaleImage(RImage * image, unsigned new_width, unsigned new_height); + +RImage *RMakeTiledImage(RImage * tile, unsigned width, unsigned height); + +RImage *RMakeCenteredImage(RImage * image, unsigned width, unsigned height, + RColor * color); + +/* + * Drawing + */ +Bool RGetPixel(RImage * image, int x, int y, RColor * color); + +void RPutPixel(RImage * image, int x, int y, RColor * color); + +void ROperatePixel(RImage * image, int operation, int x, int y, RColor * color); + +void RPutPixels(RImage * image, RPoint * points, int npoints, int mode, + RColor * color); + +void ROperatePixels(RImage * image, int operation, RPoint * points, + int npoints, int mode, RColor * color); + +int RDrawLine(RImage * image, int x0, int y0, int x1, int y1, RColor * color); + +int ROperateLine(RImage * image, int operation, int x0, int y0, int x1, int y1, + RColor * color); + +void RDrawLines(RImage * image, RPoint * points, int npoints, int mode, + RColor * color); + +void ROperateLines(RImage * image, int operation, RPoint * points, int npoints, + int mode, RColor * color); + +void RDrawSegments(RImage * image, RSegment * segs, int nsegs, RColor * color); + +void ROperateSegments(RImage * image, int operation, RSegment * segs, int nsegs, + RColor * color); + +/* + * Color convertion + */ +void RRGBtoHSV(RColor * color, RHSVColor * hsv); +void RHSVtoRGB(RHSVColor * hsv, RColor * rgb); + +/* + * Painting + */ +void RClearImage(RImage * image, RColor * color); + +void RBevelImage(RImage * image, int bevel_type); + +RImage *RRenderGradient(unsigned width, unsigned height, RColor * from, + RColor * to, int style); + + +RImage *RRenderMultiGradient(unsigned width, unsigned height, RColor ** colors, + int style); + +/* + * Convertion into X Pixmaps + */ +int RConvertImage(RContext * context, RImage * image, Pixmap * pixmap); + +int RConvertImageMask(RContext * context, RImage * image, Pixmap * pixmap, + Pixmap * mask, int threshold); + + +/* + * misc. utilities + */ +RXImage *RCreateXImage(RContext * context, int depth, + unsigned width, unsigned height); + +void RDestroyXImage(RContext * context, RXImage * ximage); + +void RPutXImage(RContext * context, Drawable d, GC gc, RXImage * ximage, + int src_x, int src_y, int dest_x, int dest_y, + unsigned width, unsigned height); + +/* do not free the returned string! */ +const char *RMessageForError(int errorCode); + +int RBlurImage(RImage * image); + +/****** Global Variables *******/ + +extern int RErrorCode; + +#endif diff --git a/wmglobe/src/zapnum.h b/wmglobe/src/zapnum.h new file mode 100644 index 0000000..db614ec --- /dev/null +++ b/wmglobe/src/zapnum.h @@ -0,0 +1,80 @@ +/* WMGlobe 0.5.pre1 - All the Earth on a WMaker Icon + * copyright (C) 1998,99 Jerome Dumonteil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************/ + +int zapnum[14][4] = +{ + {90, 0, 10, 13}, + {0, 0, 10, 13}, + {10, 0, 10, 13}, + {20, 0, 10, 13}, + {30, 0, 10, 13}, + {40, 0, 10, 13}, + {50, 0, 10, 13}, + {60, 0, 10, 13}, + {70, 0, 10, 13}, + {80, 0, 10, 13}, + {100, 0, 10, 13}, + {110, 0, 10, 13}, + {100, 0, 5, 13}, + {114, 0, 5, 13} +}; + +/* + * int zapnum2[14][4] = + * { + * {72, 0, 8, 13}, + * {0, 0, 8, 13}, + * {8, 0, 8, 13}, + * {16, 0, 8, 13}, + * {24, 0, 8, 13}, + * {32, 0, 8, 13}, + * {40, 0, 8, 13}, + * {48, 0, 8, 13}, + * {56, 0, 8, 13}, + * {64, 0, 8, 13}, + * {80, 0, 8, 13}, + * {88, 0, 8, 13}, + * {80, 0, 6, 13}, + * {92, 0, 6, 13} + * }; + */ + +int platd[4][2] = +{ + {2, 12}, + {6, 12}, + {16, 12}, + {26, 12} +}; +int platm[2][2] = +{ + {42, 12}, + {52, 12} +}; +int plongd[4][2] = +{ + {2, 36}, + {6, 36}, + {16, 36}, + {26, 36} +}; +int plongm[2][2] = +{ + {42, 36}, + {52, 36} +}; diff --git a/wmglobe/src/zapnum.xpm b/wmglobe/src/zapnum.xpm new file mode 100644 index 0000000..4207da6 --- /dev/null +++ b/wmglobe/src/zapnum.xpm @@ -0,0 +1,19 @@ +/* XPM */ +static char * zapnum_xpm[] = { +"120 13 3 1", +" c None", +". c #000000", +"+ c #CCCC6E", +"........................................................................................................................", +"...++++......++++......+++++.......+++....+++++++......+++...++++++++....+++++.....+++++.....+++++......................", +"..+++++....+++.+++...+++..++++....++++....+++++++....+++.....++++++++...++..+++...+++.+++...+++.+++.....................", +"....+++....+++..+++..+++...+++...+++++....++........+++......+.....+...+++...+++.+++...+++..++...++.....................", +"....+++....+++..+++..+++...+++..++.+++....++........++++++...+....++...+++...+++.+++...+++.+++...+++....................", +"....+++.........+++.......+++..++..+++....++++++...+++..+++.......+.....++++.++..+++...+++.+++...+++..............+++++.", +"....+++........+++.....+++++..++...+++........+++..+++...+++.....++......+++++...+++...+++.+++...+++..............+++++.", +"....+++.......+++.........++++++++++++++.......+++.+++...+++....++......++.++++...+++..+++.+++...+++....................", +"....+++......+++.....++....+++++++++++++..++...+++.+++...+++....++.....+++..++++...++++++..+++...+++....................", +"....+++.....+++...+..+++...+++.....+++...+++...+++.+++...+++...++......+++...+++......+++...++...++.....................", +"....+++....++++++++..+++..+++......+++...++++.+++...+++.+++....++.......+++..++......+++....+++.+++.....................", +"..+++++++..++++++++....+++++.......+++....+++++......+++++....++.........+++++.....+++.......+++++......................", +"..................................................................................++...................................."}; diff --git a/wmglobe/src/zaptxt.xpm b/wmglobe/src/zaptxt.xpm new file mode 100644 index 0000000..18b376b --- /dev/null +++ b/wmglobe/src/zaptxt.xpm @@ -0,0 +1,16 @@ +/* XPM */ +static char * zaptxt_xpm[] = { +"434 10 3 1", +" c None", +". c #000000", +"+ c #CCCC6E", +"..............................................................................................................................................................................................................................................+..................................................................................++.++................++++++.+.+.+...++.++.....++++.++++..+......++.............+.................................", +".+++....++...+++...+++.....++.+++++...++..+++++..+++...+++....................................................................................................................................................................................+..++..............................................++....+.+....+.................++...++...............+++++++.+.+...++...++....++.....++..+......++...++++..++..+.................................", +"++.++..+++..++.++.++.++...+++.++.....++...++.++.++.++.++.++.........+...++++...+++..++++..+++++.+++++..+++..++.++.++++....+++.++.++.++....+...+.+..++..+++..++++...+++..++++...+++.++++++.++.++.++.++.++.++.++.++.++.++.+++++................+...++............................+.+..............+..+...+.+....+.........++++....++...++....++....+....++++++.+.+.+..++...++....++.....++...+.....++..++..++.++.+..................................", +"++.++...++.....++....++...+++.++....++.......++.++.++.++.++...+....+++..++.++.++.++.++.++.++....++....++.++.++.++..++......++.++.++.++....++.++.++.++.++.++.++.++.++.++.++.++.++.++..++...++.++.++.++.++.++.++.++.++.++....++.........++.....+...++.....+......................+.+.....++++.....+..+...+.+...+.........++..++..++.....++..+..+..+.+.+.+++++++.+.+...++...++....++.....++...+.....++......++....+..................................", +"++.++...++....++....++...++++.++++..++++.....++..+++..++.++...+...++.++.++.++.++....++.++.++....++....++....++.++..++......++.++++..++....+++++.+++++.++.++.++.++.++.++.++.++.++.....++...++.++.++.++.+++++.+++++.++.++...+++.........++....+....++...+.+.+..............+++..+++++..++....++....++....................++.+++..++.....++..+.+......+..++++++.+.+.+..++...++....++.....++....+....++.....++....+....+++............................", +"++.++...++....++.....++..+.++....++.++.++...++..++.++..++++.+++++.++.++.++++..++....++.++.++++..++++..+++++.+++++..++......++.+++...++....+++++.+++++.++.++.++++..++.++.++++...+++...++...++.++.++.++.+++++..+++...+++...+++................+....++....+++...+++...............+.+.++........++........................++.+++..++.....++...+..........+++++++.+.+..++.....++...++.....++....+....++....++.....+...++.++...........................", +"++.++...++...++......++.++.++....++.++.++...++..++.++....++...+...+++++.++.++.++....++.++.++....++....++.++.++.++..++...++.++.++++..++....+++++.+++++.++.++.++....++.++.+++......++..++...++.++.++.++.+++++.+++++..+++..+++................+.....++...+.+.+..............+++..+++++..++....++..........................++.++...++.....++..+.+.+.......++++++.+.+.+..++...++....++.....++.....+...++....++....+....++.++...........................", +"++.++...++...++...++.++.+++++.++.++.++.++..++...++.++...++....+...++.++.++.++.++.++.++.++.++....++....++.++.++.++..++...++.++.++.++.++....++.++.++.++.++.++.++....++.++.++++..++.++..++...++.++..+++..++.++.++.++..+++..++............++...+............+...........++.........+.+.....++++..........................+.++......++.....++..+..+........+++++++.+.+...++...++....++.....++.....+...++..........+....++.++...........................", +".+++....++..+++++..+++.....++..+++...+++...++....+++...++.........++.++.++++...+++..++++..+++++.++.....++++.++.++.++++...+++..++.++.+++++.++.++.++..+..+++..++.....+++..++.++..+++...++....+++....+...+...+.++.++..+++..+++++.........++..+......++.................++.........+.+..................................++..++++....++...++....++.+.......++++++.+.+.+..++...++....++.....++......+..++....++...+..++..+++............................", +".....................................................................................................................................................................++...................................................................+.........................................................................+............+...+................+++++++.+.+....++.++.....++++.++++......+..++.........+..++................................."}; diff --git a/wmglobe/wmglobe.1 b/wmglobe/wmglobe.1 new file mode 100644 index 0000000..c3aff14 --- /dev/null +++ b/wmglobe/wmglobe.1 @@ -0,0 +1,242 @@ +.TH WMGlobe 1 "fevrier 1999" +.SH NAME +WMGlobe - The Whole Earth spinning on you desktop... +as a dockable app for WindowMaker +.SH SYNOPSIS +.B wmglobe +.I "[-options]" +.SH "DESCRIPTION" +WMGlobe is a WindowMaker dock.app that displays the earth on an icon. It's +an adaptation of XGlobe to WMaker environnement. WMGlobe uses a map which is +rendered on a sphere by raytracing. Yes, for a 64x64 pixel result:-) +.SH "OPTIONS" +.TP +.B \-v +version. Currently, this should display : + +WMGlobe v.0.5 6 fev 1999 +.TP +.B \-h +short help +.TP +.B \-zoom \fI zoom_value\fP +Value > 1 to magnify the view, value < 1 to lower. Default: 1.0 +.TP +.B \-pos \fI latitude longitude\fP +Initial viewing fixed at this position, don't follow +the sun rotation. Accepted values in the form 45°12'36 or 45.21 or 45:12:36 . +Default: the initial position is "under" the sun, and +the point of view follows the sun. +.TP +.B \-rand +New random position at every refresh of screen. +.TP +.B \-map \fI map_file\fP +Map used for the rendering. Can be JPEG, GIG, XPM +PNM, TIFF but none BMP. +Default: use internal map of earth. +.TP +.B \-nimap \fI night_file\fP +Map used for the dark side of the earth. Must be of +the same width x height as the day side map. +Default: if the default internal day map is used, use +a default internal night file (see -nonimap option). +If a custom day map is provided, and no night map, the +dark side is computed via the -light option. +.TP +.B \-nonimap +Don't use the default night map. +.TP +.B \-delay \fI seconds\fP +Time in seconds between each calculation of a new +position. Limited to 0.04 at compile time (25 frames +per second should be enough). The sun position move +only once per minute, so if you use wmglobe without +-dlong or -accel option, the CPU cost of WMGlobe is +*very* low. The use of very low value for -delay plus +-dlong and -accel can be CPU costly (but very nice...). +Default: 1.0 sec. +.TP +.B \-dlat \fI delta_latitude\fP +Move the point of view by delta_lat degrees per second, +with a value of 6 the earth make a full rotation in +one minute. The value can be formated as -pos option. +Default: 0°0'0 +.TP +.B \-dlong \fI delta_long\fP +Move the point of view by delta_long degrees per +second. With a value of -0°0'15" the earth make a full +rotation in 24 hours toward the west. By default, +-dlong and -dlat are null. If they are used, the view +follow their values. Going back to "follow sun" mode +in parameters screen put -dlat and -dlong to zero. +.TP +.B \-light \fI light_value\fP +Level of light of the dark side when there is no +night map, from 0 to 1. +Default: 0.25 +.TP +.B \-dawn \fI dawn_value\fP +Level of continuity for dawn limit, from 0 to 1. With +a value of 1, the border line between night and day is +at maximum contrast. +Default: 0.2 +.TP +.B \-bord \fI border_num\fP +0 1 or 2. There are 3 different borders for the icon. +Default: 0 +.TP +.B \-accel \fI time_multi\fP +Time warp factor. With -accel 24, the sun make a full +rotation in one hour (or the earth, I'm not sure). Default: 1.0 +.TP +.B \-time \fI seconds\fP +Time to display in seconds since 01-01-1970 (see the +date command). Necessary if you need to be sure that +WMGlobe is Y2K compliant without changing system time. +Negative values for dates before 1970 accepted. +Default: not set, use current time. +.TP +.B \-fun \fI dx dy\fP +Move the earth image by dx dy pixels in the icon. See +puzzle.sh to understand why. +.TP +.B \-oz +Start in "austral" mode (for "down under" people) +.TP +.B \-d \fI display\fP +Select another display +.TP +.B \-w \-shape +Useless, since it is set by default (WMaker dockable +application) +.SH "MOUSE OPTIONS" +.TP +.B left button +Change longitude while pressed, change longitude & +latitude if shift+left button. +.TP +.B middle button +Zoom in, shift + middle button: zoom out +.TP +.B right button +Displays 7 screens of parameters. On every screen, just +clic with left or right button on the figures to change +their value. The TIME screen shows an approximation +of date and time of the earth zone currently displayed, +using GMT time + longitude offset, it's close to the +real local time by one or two hours. Others options +don't need more help. Intuitive they said... +.SH "FILES" +.TP +.B MAPS +Like XGlobe, WMGlobe needs a longitude/latitude map to work. By default, +it uses a low quality built-in map of earth. But you will probably want +to use better ones. +You can get maps usable with WMGlobe on the net. See the links below. + +using custom maps: + +For the image to be mapped correctly, position 0°North 0°West must be in +the center of the image and the latitude must be linear from 90°N to 90°S. +When using a night map, make sure that day and night map have the same +dimensions. +.TP +.B Links: Where to find maps and similar softs + +where to find the sources of wmglobe: +the web page of WMGlobe (made by Sylvestre Taburet): + + + + +where to find maps and similar softs: + +Earth image by a cgi: + + + +two softs running under X: + +XGlobe Homepage: (many links to map of earth) + + + + +Xearth Homepage: + + + +By the way, you can use maps of Mars, Luna ... and text. + +.SH "ENVIRONMENT" +.LP +WMGlobe uses the setlocale(3) function, so you LANG environment need to be ok. + +You need WindowMaker 0.20.3 or 0.51.0 installed to use WMGlobe. +.SH "SEE ALSO" +.LP +The Window Maker User Guide + +The Window Maker FAQ + +.SH "AUTHOR" +jerome dumonteil + +Patches, bug reports, and suggestions are welcome. + +.SH "CREDITS" +WMGlobe is Copyright (C) 1998,99 by Jerome Dumonteil and licensed through +the GNU General Public License. +Read the COPYING file for the complete GNU license. + +Original idea, tests, logos: + +Sylvestre Taburet + +The code in 'sunpos.cpp' is taken from Xearth by Kirk Lauritz Johnson. + +/* +sunpos.c +kirk johnson +july 1993 + +code for calculating the position on the earth's surface for which +the sun is directly overhead (adapted from _practical astronomy +with your calculator, third edition_, peter duffett-smith, +cambridge university press, 1988.) + + +Copyright (C) 1989, 1990, 1993, 1994, 1995 Kirk Lauritz Johnson + +Parts of the source code (as marked) are: + Copyright (C) 1989, 1990, 1991 by Jim Frost + Copyright (C) 1992 by Jamie Zawinski + +Permission to use, copy, modify and freely distribute xearth for +non-commercial and not-for-profit purposes is hereby granted +without fee, provided that both the above copyright notice and this +permission notice appear in all copies and in supporting +documentation. +*/ + + +The rendering engine is taken from XGlobe by Thorsten Scheuermann +XGlobe Homepage: http://www.uni-karlsruhe.de/~uddn/xglobe + +Raster graphics library by Alfredo K. Kojima, & stuff of Window Maker + by A. K. Kojima, Dan Pascu, Matthew Hawkins & team + + +.SH "BUGS" +.LP +If you use the --enable-single-icon compile time option of WindowMaker, +you can not display more than one WMGlobe. + +WMGlobe hopes that an overflow of a long integer dont generate an error +and that LONG_MAX +1 = LONG_MIN . This happens with high values of -accel +when the date go over year 2038. The expected result is wmglobe +continuing smoothly from 1901. + + + diff --git a/wmglobe/wmgmap.gif b/wmglobe/wmgmap.gif new file mode 100644 index 0000000..759d194 Binary files /dev/null and b/wmglobe/wmgmap.gif differ